diff --git a/client/src/components/chat.tsx b/client/src/components/chat.tsx index cd2f4ff..7f53431 100644 --- a/client/src/components/chat.tsx +++ b/client/src/components/chat.tsx @@ -241,7 +241,6 @@ export function Hints({ hints, conclusion, counter=undefined } : { export function ChatPanel ({visible = true}) { let { t } = useTranslation() - const chatRef = useRef(null) const { mobile } = useContext(PreferencesContext) const { gameId, worldId, levelId } = useContext(GameIdContext) @@ -255,7 +254,7 @@ export function ChatPanel ({visible = true}) { const [introText, setIntroText] = useState>([]) const [chatMessages, setChatMessages] = useState>([]) - const { deletedChat, showHelp, selectedStep } = useContext(ChatContext) + const { chatRef, deletedChat, showHelp, selectedStep } = useContext(ChatContext) const { proof } = useContext(ProofContext) const readIntro = useSelector(selectReadIntro(gameId, worldId)) @@ -316,26 +315,32 @@ export function ChatPanel ({visible = true}) { setChatMessages(messages) }, [gameInfo, levelInfo, gameId, worldId, levelId, proof]) - // Scroll to the top when loading a new page + // Scroll the chat useEffect(() => { - console.debug(`scroll chat: top`) - chatRef.current!.scrollTo(0,0) - }, [completed, gameId, worldId, levelId]) + if (levelId > 0) { - // Scroll to first message of the last step. - // If the proof is currently completed, scroll to the conclusion - useEffect(() => { - if (levelId > 0 && proof) { - if (proof?.completed) { - console.debug('scroll chat: down to conclusion') - chatRef.current!.lastElementChild?.scrollIntoView({block: "center"}) + if (proof) { + if (proof?.completed) { + // proof currently completed: scroll down + console.debug('scroll chat: down to conclusion') + chatRef.current!.lastElementChild?.scrollIntoView({block: "center"}) + } else { + // proof currently not completed: first message of last step + let lastStep = proof?.steps.length - (lastStepHasErrors(proof) ? 2 : 1) + console.debug(`scroll chat: first message of step ${lastStep}`) + chatRef.current?.getElementsByClassName(`step-${lastStep}`)[0]?.scrollIntoView({block: "center"}) + } } else { - let lastStep = proof?.steps.length - (lastStepHasErrors(proof) ? 2 : 1) - console.debug(`scroll chat: first message of step ${lastStep}`) - chatRef.current?.getElementsByClassName(`step-${lastStep}`)[0]?.scrollIntoView({block: "center"}) + // no proof available: scroll to top. + console.debug(`scroll chat: top`) + chatRef.current!.scrollTo(0,0) } + } else { + // introduction: scroll to last message + console.debug('scroll chat: down') + chatRef.current!.lastElementChild?.scrollIntoView({block: "center"}) } - }, [chatMessages, gameId, worldId, levelId]) + }, [counter, introText, chatMessages, gameId, worldId, levelId]) // Scroll down when new hidden hints are triggered useEffect(() => { @@ -343,6 +348,7 @@ export function ChatPanel ({visible = true}) { let lastStep = proof?.steps.length - (lastStepHasErrors(proof) ? 2 : 1) if (showHelp.has(lastStep)) { console.debug('scroll chat: down to hidden hints') + // TODO: last element of hidden hints? chatRef.current!.lastElementChild?.scrollIntoView({block: "center"}) } } diff --git a/client/src/components/game.tsx b/client/src/components/game.tsx index 75e6d5a..34262d1 100644 --- a/client/src/components/game.tsx +++ b/client/src/components/game.tsx @@ -54,6 +54,7 @@ function Game() { // const [pageNumber, setPageNumber] = React.useState(readIntro ? 1 : 0) + const chatRef = useRef(null) // When deleting the proof, we want to keep to old messages around until // a new proof has been entered. e.g. to consult messages coming from dead ends const [deletedChat, setDeletedChat] = useState>([]) @@ -93,7 +94,7 @@ function Game() { setShowHelp(new Set()) }, [gameId, worldId, levelId]) - return + return { mobile ?
diff --git a/client/src/components/infoview/context.ts b/client/src/components/infoview/context.ts index afa5d5d..3f13dcb 100644 --- a/client/src/components/infoview/context.ts +++ b/client/src/components/infoview/context.ts @@ -95,19 +95,21 @@ export const PreferencesContext = React.createContext({ export const ChatContext = React.createContext<{ - selectedStep : number, + selectedStep : number setSelectedStep: React.Dispatch> - deletedChat : GameHint[], + deletedChat : GameHint[] setDeletedChat: React.Dispatch>> - showHelp : Set, + showHelp : Set setShowHelp: React.Dispatch>> + chatRef: React.MutableRefObject }>({ selectedStep : undefined, setSelectedStep: () => {}, deletedChat: undefined, setDeletedChat: () => {}, showHelp: undefined, - setShowHelp: () => {} + setShowHelp: () => {}, + chatRef: null }) export const PageContext = React.createContext<{