improve chat scrolling #82

pull/251/merge
Jon Eugster 2 years ago
parent 7dc0a507ed
commit f158250341

@ -241,7 +241,6 @@ export function Hints({ hints, conclusion, counter=undefined } : {
export function ChatPanel ({visible = true}) {
let { t } = useTranslation()
const chatRef = useRef<HTMLDivElement>(null)
const { mobile } = useContext(PreferencesContext)
const { gameId, worldId, levelId } = useContext(GameIdContext)
@ -255,7 +254,7 @@ export function ChatPanel ({visible = true}) {
const [introText, setIntroText] = useState<Array<GameHintWithStep>>([])
const [chatMessages, setChatMessages] = useState<Array<GameHintWithStep>>([])
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"})
}
}

@ -54,6 +54,7 @@ function Game() {
// const [pageNumber, setPageNumber] = React.useState(readIntro ? 1 : 0)
const chatRef = useRef<HTMLDivElement>(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<Array<GameHint>>([])
@ -93,7 +94,7 @@ function Game() {
setShowHelp(new Set())
}, [gameId, worldId, levelId])
return <ChatContext.Provider value={{selectedStep, setSelectedStep, deletedChat, setDeletedChat, showHelp, setShowHelp}}>
return <ChatContext.Provider value={{selectedStep, setSelectedStep, deletedChat, setDeletedChat, showHelp, setShowHelp, chatRef}}>
<ProofContext.Provider value={{proof, setProof, interimDiags, setInterimDiags, crashed: isCrashed, setCrashed: setIsCrashed}}>
{ mobile ?
<div className="app-content mobile">

@ -95,19 +95,21 @@ export const PreferencesContext = React.createContext<IPreferencesContext>({
export const ChatContext = React.createContext<{
selectedStep : number,
selectedStep : number
setSelectedStep: React.Dispatch<React.SetStateAction<number>>
deletedChat : GameHint[],
deletedChat : GameHint[]
setDeletedChat: React.Dispatch<React.SetStateAction<Array<GameHint>>>
showHelp : Set<number>,
showHelp : Set<number>
setShowHelp: React.Dispatch<React.SetStateAction<Set<number>>>
chatRef: React.MutableRefObject<HTMLDivElement>
}>({
selectedStep : undefined,
setSelectedStep: () => {},
deletedChat: undefined,
setDeletedChat: () => {},
showHelp: undefined,
setShowHelp: () => {}
setShowHelp: () => {},
chatRef: null
})
export const PageContext = React.createContext<{

Loading…
Cancel
Save