diff --git a/src/renderer/src/pages/home/Chat.tsx b/src/renderer/src/pages/home/Chat.tsx index 7846a1a7..d44b53c6 100644 --- a/src/renderer/src/pages/home/Chat.tsx +++ b/src/renderer/src/pages/home/Chat.tsx @@ -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 diff --git a/src/renderer/src/pages/home/Messages/ChatNavigation.tsx b/src/renderer/src/pages/home/Messages/ChatNavigation.tsx index 3f9c0c96..68f07402 100644 --- a/src/renderer/src/pages/home/Messages/ChatNavigation.tsx +++ b/src/renderer/src/pages/home/Messages/ChatNavigation.tsx @@ -24,7 +24,6 @@ const ChatNavigation: FC = ({ 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 = ({ containerId }) => { clearTimeout(hideTimer) } } - }, [ - containerId, - hideTimer, - resetHideTimer, - isNearButtons, - handleMouseEnter, - handleMouseLeave, - right, - showRightTopics - ]) + }, [containerId, hideTimer, resetHideTimer, isNearButtons, handleMouseEnter, handleMouseLeave, showRightTopics]) return ( <> - + = ({ containerId }) => { interface NavigationContainerProps { $isVisible: boolean - $right: string } const NavigationContainer = styled.div` position: fixed; - right: ${(props) => props.$right}; + right: 16px; top: 50%; transform: translateY(-50%) translateX(${(props) => (props.$isVisible ? 0 : '100%')}); z-index: 999; diff --git a/src/renderer/src/pages/home/Messages/MessageAnchorLine.tsx b/src/renderer/src/pages/home/Messages/MessageAnchorLine.tsx index be70d8f4..85ae773f 100644 --- a/src/renderer/src/pages/home/Messages/MessageAnchorLine.tsx +++ b/src/renderer/src/pages/home/Messages/MessageAnchorLine.tsx @@ -33,9 +33,6 @@ const MessageAnchorLine: FC = ({ messages }) => { const messageItemsRef = useRef>(new Map()) const containerRef = useRef(null) const [mouseY, setMouseY] = useState(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(null) @@ -160,7 +157,6 @@ const MessageAnchorLine: FC = ({ messages }) => { ref={containerRef} onMouseMove={handleMouseMove} onMouseLeave={handleMouseLeave} - $right={right} $height={containerHeight}> {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; diff --git a/src/renderer/src/pages/home/Messages/MessageGroup.tsx b/src/renderer/src/pages/home/Messages/MessageGroup.tsx index b62f6f50..6719ef28 100644 --- a/src/renderer/src/pages/home/Messages/MessageGroup.tsx +++ b/src/renderer/src/pages/home/Messages/MessageGroup.tsx @@ -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() })}> @@ -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} /> diff --git a/src/renderer/src/pages/home/Messages/MessageGroupMenuBar.tsx b/src/renderer/src/pages/home/Messages/MessageGroupMenuBar.tsx index 0dceb3ad..c8471efd 100644 --- a/src/renderer/src/pages/home/Messages/MessageGroupMenuBar.tsx +++ b/src/renderer/src/pages/home/Messages/MessageGroupMenuBar.tsx @@ -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 = ({ multiModelMessageStyle, setMultiModelMessageStyle, messages, + selectMessageId, setSelectedMessage, topic }) => { @@ -75,7 +77,11 @@ const MessageGroupMenuBar: FC = ({ ))} {multiModelMessageStyle === 'fold' && ( - + )} {multiModelMessageStyle === 'grid' && } diff --git a/src/renderer/src/pages/home/Messages/MessageGroupModelList.tsx b/src/renderer/src/pages/home/Messages/MessageGroupModelList.tsx index 695d3a05..9045beca 100644 --- a/src/renderer/src/pages/home/Messages/MessageGroupModelList.tsx +++ b/src/renderer/src/pages/home/Messages/MessageGroupModelList.tsx @@ -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 = ({ messages, setSelectedMessage }) => { +const MessageGroupModelList: FC = ({ messages, selectMessageId, setSelectedMessage }) => { const dispatch = useAppDispatch() const { t } = useTranslation() const { foldDisplayMode } = useSettings() @@ -47,7 +48,7 @@ const MessageGroupModelList: FC = ({ messages, setSe { setSelectedMessage(message) }}> @@ -59,7 +60,7 @@ const MessageGroupModelList: FC = ({ messages, setSe ) : ( /* Expanded style display */ message.foldSelected)?.id || messages[0].id} + value={selectMessageId} onChange={(value) => { const message = messages.find((message) => message.id === value) as Message setSelectedMessage(message) diff --git a/src/renderer/src/store/messages.ts b/src/renderer/src/store/messages.ts index 510d409e..6e244b89 100644 --- a/src/renderer/src/store/messages.ts +++ b/src/renderer/src/store/messages.ts @@ -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) }