fix: fix fold selected (#4058)

* fix: 修复foldSelected问题

* refactor: 优化布局定位
This commit is contained in:
Teo 2025-03-28 21:22:45 +08:00 committed by GitHub
parent f1a03916e7
commit 21f1b8b373
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 63 additions and 49 deletions

View File

@ -56,6 +56,8 @@ const Container = styled.div`
const Main = styled(Flex)`
height: calc(100vh - var(--navbar-height));
// 设置为containing block方便子元素fixed定位
transform: translateZ(0);
`
export default Chat

View File

@ -24,7 +24,6 @@ const ChatNavigation: FC<ChatNavigationProps> = ({ containerId }) => {
const lastMoveTime = useRef(0)
const { topicPosition, showTopics } = useSettings()
const showRightTopics = topicPosition === 'right' && showTopics
const right = showRightTopics ? 'calc(var(--topic-list-width) + 16px)' : '16px'
// Reset hide timer and make buttons visible
const resetHideTimer = useCallback(() => {
@ -263,24 +262,11 @@ const ChatNavigation: FC<ChatNavigationProps> = ({ containerId }) => {
clearTimeout(hideTimer)
}
}
}, [
containerId,
hideTimer,
resetHideTimer,
isNearButtons,
handleMouseEnter,
handleMouseLeave,
right,
showRightTopics
])
}, [containerId, hideTimer, resetHideTimer, isNearButtons, handleMouseEnter, handleMouseLeave, showRightTopics])
return (
<>
<NavigationContainer
$isVisible={isVisible}
$right={right}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}>
<NavigationContainer $isVisible={isVisible} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
<ButtonGroup>
<Tooltip title={t('chat.navigation.prev')} placement="left">
<NavigationButton
@ -332,12 +318,11 @@ const ChatNavigation: FC<ChatNavigationProps> = ({ containerId }) => {
interface NavigationContainerProps {
$isVisible: boolean
$right: string
}
const NavigationContainer = styled.div<NavigationContainerProps>`
position: fixed;
right: ${(props) => props.$right};
right: 16px;
top: 50%;
transform: translateY(-50%) translateX(${(props) => (props.$isVisible ? 0 : '100%')});
z-index: 999;

View File

@ -33,9 +33,6 @@ const MessageAnchorLine: FC<MessageLineProps> = ({ messages }) => {
const messageItemsRef = useRef<Map<string, HTMLDivElement>>(new Map())
const containerRef = useRef<HTMLDivElement>(null)
const [mouseY, setMouseY] = useState<number | null>(null)
const { topicPosition, showTopics } = useSettings()
const showRightTopics = topicPosition === 'right' && showTopics
const right = showRightTopics ? 'calc(var(--topic-list-width) + 15px)' : '15px'
const [listOffsetY, setListOffsetY] = useState(0)
const [containerHeight, setContainerHeight] = useState<number | null>(null)
@ -160,7 +157,6 @@ const MessageAnchorLine: FC<MessageLineProps> = ({ messages }) => {
ref={containerRef}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
$right={right}
$height={containerHeight}>
<MessagesList ref={messagesListRef} style={{ transform: `translateY(${listOffsetY}px)` }}>
{messages.map((message, index) => {
@ -226,11 +222,11 @@ const MessageItemContainer = styled.div`
transform-origin: right center;
`
const MessageLineContainer = styled.div<{ $right: string; $height: number | null }>`
const MessageLineContainer = styled.div<{ $height: number | null }>`
width: 14px;
position: fixed;
top: ${(props) => (props.$height ? `calc(${props.$height / 2}px + var(--status-bar-height))` : '50%')};
right: ${(props) => props.$right};
right: 13px;
max-height: ${(props) => (props.$height ? `${props.$height}px` : 'calc(100% - var(--status-bar-height) * 2)')};
transform: translateY(-50%);
z-index: 0;

View File

@ -6,7 +6,7 @@ import { MultiModelMessageStyle } from '@renderer/store/settings'
import type { Message, Topic } from '@renderer/types'
import { classNames } from '@renderer/utils'
import { Popover } from 'antd'
import { memo, useCallback, useEffect, useState } from 'react'
import { memo, useCallback, useEffect, useRef, useState } from 'react'
import styled, { css } from 'styled-components'
import MessageGroupMenuBar from './MessageGroupMenuBar'
@ -27,14 +27,53 @@ const MessageGroup = ({ messages, topic, hidePresetMessages }: Props) => {
)
const messageLength = messages.length
const prevMessageLengthRef = useRef(messageLength)
const [selectedIndex, setSelectedIndex] = useState(messageLength - 1)
const getSelectedMessageId = useCallback(() => {
const selectedMessage = messages.find((message) => message.foldSelected)
if (selectedMessage) {
return selectedMessage.id
}
return messages[0]?.id
}, [messages])
const setSelectedMessage = useCallback(
(message: Message) => {
messages.forEach(async (m) => {
await editMessage(m.id, { foldSelected: m.id === message.id })
})
setTimeout(() => {
const messageElement = document.getElementById(`message-${message.id}`)
if (messageElement) {
messageElement.scrollIntoView({ behavior: 'smooth', block: 'start' })
}
}, 200)
},
[editMessage, messages]
)
const isGrouped = messageLength > 1 && messages.every((m) => m.role === 'assistant')
const isHorizontal = multiModelMessageStyle === 'horizontal'
const isGrid = multiModelMessageStyle === 'grid'
useEffect(() => {
setSelectedIndex(messageLength - 1)
if (messageLength > prevMessageLengthRef.current) {
setSelectedIndex(messageLength - 1)
const lastMessage = messages[messageLength - 1]
if (lastMessage) {
setSelectedMessage(lastMessage)
}
} else {
const selectedId = getSelectedMessageId()
const newIndex = messages.findIndex((msg) => msg.id === selectedId)
if (newIndex !== -1) {
setSelectedIndex(newIndex)
}
}
prevMessageLengthRef.current = messageLength
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [messageLength])
// 添加对流程图节点点击事件的监听
@ -70,22 +109,6 @@ const MessageGroup = ({ messages, topic, hidePresetMessages }: Props) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [messages, selectedIndex, isGrouped, messageLength])
const setSelectedMessage = useCallback(
(message: Message) => {
messages.forEach(async (m) => {
await editMessage(m.id, { foldSelected: m.id === message.id })
})
setTimeout(() => {
const messageElement = document.getElementById(`message-${message.id}`)
if (messageElement) {
messageElement.scrollIntoView({ behavior: 'smooth', block: 'start' })
}
}, 200)
},
[editMessage, messages]
)
// 添加对LOCATE_MESSAGE事件的监听
useEffect(() => {
// 为每个消息注册一个定位事件监听器
@ -146,7 +169,7 @@ const MessageGroup = ({ messages, topic, hidePresetMessages }: Props) => {
className={classNames({
'group-message-wrapper': message.role === 'assistant' && isHorizontal && isGrouped,
[multiModelMessageStyle]: isGrouped,
selected: 'foldSelected' in message ? message.foldSelected : index === 0
selected: message.id === getSelectedMessageId()
})}>
<MessageStream {...messageProps} />
</MessageWrapper>
@ -183,7 +206,8 @@ const MessageGroup = ({ messages, topic, hidePresetMessages }: Props) => {
selectedIndex,
topic,
hidePresetMessages,
gridPopoverTrigger
gridPopoverTrigger,
getSelectedMessageId
]
)
@ -210,6 +234,7 @@ const MessageGroup = ({ messages, topic, hidePresetMessages }: Props) => {
})
}}
messages={messages}
selectMessageId={getSelectedMessageId()}
setSelectedMessage={setSelectedMessage}
topic={topic}
/>

View File

@ -21,6 +21,7 @@ interface Props {
multiModelMessageStyle: MultiModelMessageStyle
setMultiModelMessageStyle: (style: MultiModelMessageStyle) => void
messages: Message[]
selectMessageId: string
setSelectedMessage: (message: Message) => void
topic: Topic
}
@ -29,6 +30,7 @@ const MessageGroupMenuBar: FC<Props> = ({
multiModelMessageStyle,
setMultiModelMessageStyle,
messages,
selectMessageId,
setSelectedMessage,
topic
}) => {
@ -75,7 +77,11 @@ const MessageGroupMenuBar: FC<Props> = ({
))}
</LayoutContainer>
{multiModelMessageStyle === 'fold' && (
<MessageGroupModelList messages={messages} setSelectedMessage={setSelectedMessage} />
<MessageGroupModelList
messages={messages}
selectMessageId={selectMessageId}
setSelectedMessage={setSelectedMessage}
/>
)}
{multiModelMessageStyle === 'grid' && <MessageGroupSettings />}
</HStack>

View File

@ -12,12 +12,13 @@ import styled from 'styled-components'
interface MessageGroupModelListProps {
messages: Message[]
selectMessageId: string
setSelectedMessage: (message: Message) => void
}
type DisplayMode = 'compact' | 'expanded'
const MessageGroupModelList: FC<MessageGroupModelListProps> = ({ messages, setSelectedMessage }) => {
const MessageGroupModelList: FC<MessageGroupModelListProps> = ({ messages, selectMessageId, setSelectedMessage }) => {
const dispatch = useAppDispatch()
const { t } = useTranslation()
const { foldDisplayMode } = useSettings()
@ -47,7 +48,7 @@ const MessageGroupModelList: FC<MessageGroupModelListProps> = ({ messages, setSe
<Tooltip key={index} title={message.model?.name} placement="top" mouseEnterDelay={0.2}>
<AvatarWrapper
className="avatar-wrapper"
isSelected={'foldSelected' in message ? message.foldSelected! : index === 0}
isSelected={message.id === selectMessageId}
onClick={() => {
setSelectedMessage(message)
}}>
@ -59,7 +60,7 @@ const MessageGroupModelList: FC<MessageGroupModelListProps> = ({ messages, setSe
) : (
/* Expanded style display */
<Segmented
value={messages.find((message) => message.foldSelected)?.id || messages[0].id}
value={selectMessageId}
onChange={(value) => {
const message = messages.find((message) => message.id === value) as Message
setSelectedMessage(message)

View File

@ -278,7 +278,6 @@ export const sendMessage =
const assistantMessage = getAssistantMessage({ assistant, topic })
assistantMessage.askId = userMessage.id
assistantMessage.status = 'sending'
assistantMessage.foldSelected = true
assistantMessages.push(assistantMessage)
}