mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-06 05:09:09 +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 [isScrolling, setIsScrolling] = useState(false)
|
||||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null)
|
const timeoutRef = useRef<NodeJS.Timeout | null>(null)
|
||||||
|
|
||||||
const handleScroll = useCallback(() => {
|
const clearScrollingTimeout = useCallback(() => {
|
||||||
setIsScrolling(true)
|
|
||||||
|
|
||||||
if (timeoutRef.current) {
|
if (timeoutRef.current) {
|
||||||
clearTimeout(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
|
// Combined scroll handler
|
||||||
const combinedOnScroll = useCallback(() => {
|
const combinedOnScroll = useCallback(() => {
|
||||||
// Event is available if needed by internal handler
|
throttledInternalScrollHandler()
|
||||||
throttledInternalScrollHandler() // Call internal logic
|
|
||||||
if (externalOnScroll) {
|
if (externalOnScroll) {
|
||||||
externalOnScroll() // Call external logic (from useScrollPosition)
|
externalOnScroll()
|
||||||
}
|
}
|
||||||
}, [throttledInternalScrollHandler, externalOnScroll])
|
}, [throttledInternalScrollHandler, externalOnScroll])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
timeoutRef.current && clearTimeout(timeoutRef.current)
|
clearScrollingTimeout()
|
||||||
throttledInternalScrollHandler.cancel()
|
throttledInternalScrollHandler.cancel()
|
||||||
}
|
}
|
||||||
}, [throttledInternalScrollHandler])
|
}, [throttledInternalScrollHandler, clearScrollingTimeout])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container
|
||||||
|
|||||||
@ -114,16 +114,14 @@ const Chat: FC<Props> = (props) => {
|
|||||||
includeUser={filterIncludeUser}
|
includeUser={filterIncludeUser}
|
||||||
onIncludeUserChange={userOutlinedItemClickHandler}
|
onIncludeUserChange={userOutlinedItemClickHandler}
|
||||||
/>
|
/>
|
||||||
<MessagesContainer className="messages-container">
|
<Messages
|
||||||
<Messages
|
key={props.activeTopic.id}
|
||||||
key={props.activeTopic.id}
|
assistant={assistant}
|
||||||
assistant={assistant}
|
topic={props.activeTopic}
|
||||||
topic={props.activeTopic}
|
setActiveTopic={props.setActiveTopic}
|
||||||
setActiveTopic={props.setActiveTopic}
|
onComponentUpdate={messagesComponentUpdateHandler}
|
||||||
onComponentUpdate={messagesComponentUpdateHandler}
|
onFirstUpdate={messagesComponentFirstUpdateHandler}
|
||||||
onFirstUpdate={messagesComponentFirstUpdateHandler}
|
/>
|
||||||
/>
|
|
||||||
</MessagesContainer>
|
|
||||||
<QuickPanelProvider>
|
<QuickPanelProvider>
|
||||||
<Inputbar assistant={assistant} setActiveTopic={props.setActiveTopic} topic={props.activeTopic} />
|
<Inputbar assistant={assistant} setActiveTopic={props.setActiveTopic} topic={props.activeTopic} />
|
||||||
{isMultiSelectMode && <MultiSelectActionPopup 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`
|
const Container = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|||||||
@ -53,7 +53,7 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic, o
|
|||||||
`topic-${topic.id}`
|
`topic-${topic.id}`
|
||||||
)
|
)
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { showPrompt, showTopics, topicPosition, showAssistants, messageNavigation } = useSettings()
|
const { showPrompt, topicPosition, messageNavigation } = useSettings()
|
||||||
const { updateTopic, addTopic } = useAssistant(assistant.id)
|
const { updateTopic, addTopic } = useAssistant(assistant.id)
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const [displayMessages, setDisplayMessages] = useState<Message[]>([])
|
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])
|
const groupedMessages = useMemo(() => Object.entries(getGroupedMessages(displayMessages)), [displayMessages])
|
||||||
return (
|
return (
|
||||||
<Container
|
<MessagesContainer
|
||||||
id="messages"
|
id="messages"
|
||||||
|
className="messages-container"
|
||||||
ref={scrollContainerRef}
|
ref={scrollContainerRef}
|
||||||
style={{ position: 'relative', paddingTop: showPrompt ? 10 : 0 }}
|
style={{ position: 'relative', paddingTop: showPrompt ? 10 : 0 }}
|
||||||
key={assistant.id}
|
key={assistant.id}
|
||||||
@ -304,14 +305,13 @@ const Messages: React.FC<MessagesProps> = ({ assistant, topic, setActiveTopic, o
|
|||||||
</NarrowLayout>
|
</NarrowLayout>
|
||||||
{messageNavigation === 'anchor' && <MessageAnchorLine messages={displayMessages} />}
|
{messageNavigation === 'anchor' && <MessageAnchorLine messages={displayMessages} />}
|
||||||
{messageNavigation === 'buttons' && <ChatNavigation containerId="messages" />}
|
{messageNavigation === 'buttons' && <ChatNavigation containerId="messages" />}
|
||||||
|
|
||||||
<SelectionBox
|
<SelectionBox
|
||||||
isMultiSelectMode={isMultiSelectMode}
|
isMultiSelectMode={isMultiSelectMode}
|
||||||
scrollContainerRef={scrollContainerRef}
|
scrollContainerRef={scrollContainerRef}
|
||||||
messageElements={messageElements.current}
|
messageElements={messageElements.current}
|
||||||
handleSelectMessage={handleSelectMessage}
|
handleSelectMessage={handleSelectMessage}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</MessagesContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,7 +369,7 @@ interface ContainerProps {
|
|||||||
$right?: boolean
|
$right?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const Container = styled(Scrollbar)<ContainerProps>`
|
const MessagesContainer = styled(Scrollbar)<ContainerProps>`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
padding: 10px 0 20px;
|
padding: 10px 0 20px;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user