mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-25 03:10:08 +08:00
refactor(Scrollbar, Chat, Messages): improve scroll handling and clean up component structure
This commit is contained in:
parent
c6e574d080
commit
1a4dbd1843
@ -12,33 +12,41 @@ const Scrollbar: FC<Props> = ({ ref: passedRef, right, children, onScroll: exter
|
||||
const [isScrolling, setIsScrolling] = useState(false)
|
||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null)
|
||||
|
||||
const handleScroll = useCallback(() => {
|
||||
setIsScrolling(true)
|
||||
|
||||
const clearScrollingTimeout = useCallback(() => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current)
|
||||
timeoutRef.current = null
|
||||
}
|
||||
|
||||
timeoutRef.current = setTimeout(() => setIsScrolling(false), 1500)
|
||||
}, [])
|
||||
|
||||
const throttledInternalScrollHandler = throttle(handleScroll, 200)
|
||||
const handleScroll = useCallback(() => {
|
||||
setIsScrolling(true)
|
||||
clearScrollingTimeout()
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
setIsScrolling(false)
|
||||
timeoutRef.current = null
|
||||
}, 1000)
|
||||
}, [clearScrollingTimeout])
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const throttledInternalScrollHandler = useCallback(throttle(handleScroll, 100, { leading: true, trailing: true }), [
|
||||
handleScroll
|
||||
])
|
||||
|
||||
// Combined scroll handler
|
||||
const combinedOnScroll = useCallback(() => {
|
||||
// Event is available if needed by internal handler
|
||||
throttledInternalScrollHandler() // Call internal logic
|
||||
throttledInternalScrollHandler()
|
||||
if (externalOnScroll) {
|
||||
externalOnScroll() // Call external logic (from useScrollPosition)
|
||||
externalOnScroll()
|
||||
}
|
||||
}, [throttledInternalScrollHandler, externalOnScroll])
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
timeoutRef.current && clearTimeout(timeoutRef.current)
|
||||
clearScrollingTimeout()
|
||||
throttledInternalScrollHandler.cancel()
|
||||
}
|
||||
}, [throttledInternalScrollHandler])
|
||||
}, [throttledInternalScrollHandler, clearScrollingTimeout])
|
||||
|
||||
return (
|
||||
<Container
|
||||
|
||||
@ -114,16 +114,14 @@ const Chat: FC<Props> = (props) => {
|
||||
includeUser={filterIncludeUser}
|
||||
onIncludeUserChange={userOutlinedItemClickHandler}
|
||||
/>
|
||||
<MessagesContainer className="messages-container">
|
||||
<Messages
|
||||
key={props.activeTopic.id}
|
||||
assistant={assistant}
|
||||
topic={props.activeTopic}
|
||||
setActiveTopic={props.setActiveTopic}
|
||||
onComponentUpdate={messagesComponentUpdateHandler}
|
||||
onFirstUpdate={messagesComponentFirstUpdateHandler}
|
||||
/>
|
||||
</MessagesContainer>
|
||||
<Messages
|
||||
key={props.activeTopic.id}
|
||||
assistant={assistant}
|
||||
topic={props.activeTopic}
|
||||
setActiveTopic={props.setActiveTopic}
|
||||
onComponentUpdate={messagesComponentUpdateHandler}
|
||||
onFirstUpdate={messagesComponentFirstUpdateHandler}
|
||||
/>
|
||||
<QuickPanelProvider>
|
||||
<Inputbar assistant={assistant} setActiveTopic={props.setActiveTopic} topic={props.activeTopic} />
|
||||
{isMultiSelectMode && <MultiSelectActionPopup topic={props.activeTopic} />}
|
||||
@ -142,13 +140,6 @@ const Chat: FC<Props> = (props) => {
|
||||
)
|
||||
}
|
||||
|
||||
const MessagesContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
`
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
@ -53,7 +53,7 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic, o
|
||||
`topic-${topic.id}`
|
||||
)
|
||||
const { t } = useTranslation()
|
||||
const { showPrompt, showTopics, topicPosition, showAssistants, messageNavigation } = useSettings()
|
||||
const { showPrompt, topicPosition, messageNavigation } = useSettings()
|
||||
const { updateTopic, addTopic } = useAssistant(assistant.id)
|
||||
const dispatch = useAppDispatch()
|
||||
const [displayMessages, setDisplayMessages] = useState<Message[]>([])
|
||||
@ -267,8 +267,9 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic, o
|
||||
|
||||
const groupedMessages = useMemo(() => Object.entries(getGroupedMessages(displayMessages)), [displayMessages])
|
||||
return (
|
||||
<Container
|
||||
<MessagesContainer
|
||||
id="messages"
|
||||
className="messages-container"
|
||||
ref={scrollContainerRef}
|
||||
style={{ position: 'relative', paddingTop: showPrompt ? 10 : 0 }}
|
||||
key={assistant.id}
|
||||
@ -304,14 +305,13 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic, o
|
||||
</NarrowLayout>
|
||||
{messageNavigation === 'anchor' && <MessageAnchorLine messages={displayMessages} />}
|
||||
{messageNavigation === 'buttons' && <ChatNavigation containerId="messages" />}
|
||||
|
||||
<SelectionBox
|
||||
isMultiSelectMode={isMultiSelectMode}
|
||||
scrollContainerRef={scrollContainerRef}
|
||||
messageElements={messageElements.current}
|
||||
handleSelectMessage={handleSelectMessage}
|
||||
/>
|
||||
</Container>
|
||||
</MessagesContainer>
|
||||
)
|
||||
}
|
||||
|
||||
@ -369,7 +369,7 @@ interface ContainerProps {
|
||||
$right?: boolean
|
||||
}
|
||||
|
||||
const Container = styled(Scrollbar)<ContainerProps>`
|
||||
const MessagesContainer = styled(Scrollbar)<ContainerProps>`
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
padding: 10px 0 20px;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user