fix: fix fold selected (#4058)
* fix: 修复foldSelected问题 * refactor: 优化布局定位
This commit is contained in:
parent
f1a03916e7
commit
21f1b8b373
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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(() => {
|
||||
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}
|
||||
/>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user