fix: scroll bottom issue (#4308)

This commit is contained in:
Faisal Amir 2024-12-20 23:39:08 +08:00 committed by GitHub
parent 4e43f9798d
commit af84a3a8d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 47 additions and 27 deletions

View File

@ -378,14 +378,14 @@ const ModelDropdown = ({
!selectedModel && 'text-[hsla(var(--text-tertiary))]'
)}
>
{selectedModel?.name || 'Select Model'}
{selectedModel?.name || 'Select a model'}
</span>
</Badge>
) : (
<Input
value={selectedModel?.name || ''}
className="cursor-pointer"
placeholder="Select Model"
placeholder="Select a model"
disabled={disabled}
readOnly
suffixIcon={

View File

@ -23,9 +23,7 @@ const EmptyThread = () => {
<LogoMark className="mx-auto mb-2 animate-wave" width={32} height={32} />
{showOnboardingStep ? (
<>
<p className="mt-1 font-medium">
{`You don't have a local model yet.`}
</p>
<p className="mt-1 font-medium">{`You don't have any model`}</p>
<Button
onClick={() => setMainViewState(MainViewState.Hub)}
variant="soft"

View File

@ -14,7 +14,11 @@ import LoadModelError from '../LoadModelError'
import EmptyThread from './EmptyThread'
import { getCurrentChatMessagesAtom } from '@/helpers/atoms/ChatMessage.atom'
import { activeThreadAtom } from '@/helpers/atoms/Thread.atom'
import {
activeThreadAtom,
isGeneratingResponseAtom,
threadStatesAtom,
} from '@/helpers/atoms/Thread.atom'
const ChatConfigurator = memo(() => {
const messages = useAtomValue(getCurrentChatMessagesAtom)
@ -61,6 +65,12 @@ const ChatBody = memo(
const prevScrollTop = useRef(0)
const isUserManuallyScrollingUp = useRef(false)
const currentThread = useAtomValue(activeThreadAtom)
const threadStates = useAtomValue(threadStatesAtom)
const isGeneratingResponse = useAtomValue(isGeneratingResponseAtom)
const isStreamingResponse = Object.values(threadStates).some(
(threadState) => threadState.waitingForResponse
)
const count = useMemo(
() => (messages?.length ?? 0) + (loadModelError ? 1 : 0),
@ -76,15 +86,23 @@ const ChatBody = memo(
})
useEffect(() => {
// Delay the scroll until the DOM is updated
if (parentRef.current) {
if (parentRef.current && isGeneratingResponse) {
requestAnimationFrame(() => {
if (parentRef.current) {
parentRef.current.scrollTo({ top: parentRef.current.scrollHeight })
virtualizer.scrollToIndex(count - 1)
}
})
}
}, [count, virtualizer, isGeneratingResponse])
useEffect(() => {
isUserManuallyScrollingUp.current = false
requestAnimationFrame(() => {
if (parentRef.current) {
parentRef.current.scrollTo({ top: parentRef.current.scrollHeight })
virtualizer.scrollToIndex(count - 1)
}
})
}, [count, currentThread?.id, virtualizer])
const items = virtualizer.getVirtualItems()
@ -94,34 +112,38 @@ const ChatBody = memo(
_,
instance
) => {
if (isUserManuallyScrollingUp.current === true) return false
if (isUserManuallyScrollingUp.current === true && isStreamingResponse)
return false
return (
// item.start < (instance.scrollOffset ?? 0) &&
instance.scrollDirection !== 'backward'
)
}
const handleScroll = useCallback((event: React.UIEvent<HTMLElement>) => {
const currentScrollTop = event.currentTarget.scrollTop
if (prevScrollTop.current > currentScrollTop) {
isUserManuallyScrollingUp.current = true
} else {
const handleScroll = useCallback(
(event: React.UIEvent<HTMLElement>) => {
const currentScrollTop = event.currentTarget.scrollTop
const scrollHeight = event.currentTarget.scrollHeight
const clientHeight = event.currentTarget.clientHeight
if (currentScrollTop + clientHeight >= scrollHeight) {
isUserManuallyScrollingUp.current = false
if (prevScrollTop.current > currentScrollTop && isStreamingResponse) {
isUserManuallyScrollingUp.current = true
} else {
const currentScrollTop = event.currentTarget.scrollTop
const scrollHeight = event.currentTarget.scrollHeight
const clientHeight = event.currentTarget.clientHeight
if (currentScrollTop + clientHeight >= scrollHeight) {
isUserManuallyScrollingUp.current = false
}
}
}
if (isUserManuallyScrollingUp.current === true) {
event.preventDefault()
event.stopPropagation()
}
prevScrollTop.current = currentScrollTop
}, [])
if (isUserManuallyScrollingUp.current === true) {
event.preventDefault()
event.stopPropagation()
}
prevScrollTop.current = currentScrollTop
},
[isStreamingResponse]
)
return (
<div className="flex h-full w-full flex-col overflow-x-hidden">