refactor(ThinkingEffect): optimize thinking effect (#8232)

* refactor(ThinkingEffect): optimize message rendering and adjust styles

- Removed unnecessary motion components and simplified message rendering logic.
- Updated line height and container dimensions for better layout consistency.
- Adjusted padding and width in styled components for improved visual appearance.

* fix(ThinkingBlock): remove margin-top from snapshot for consistent styling

* refactor(Message): remove unnecessary padding adjustments for assistant messages
This commit is contained in:
Teo 2025-07-17 17:40:56 +08:00 committed by GitHub
parent fe91d4b56a
commit e85ea1ff28
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 47 additions and 43 deletions

View File

@ -1,7 +1,7 @@
import { lightbulbVariants } from '@renderer/utils/motionVariants' import { lightbulbVariants } from '@renderer/utils/motionVariants'
import { isEqual } from 'lodash' import { isEqual } from 'lodash'
import { ChevronRight, Lightbulb } from 'lucide-react' import { ChevronRight, Lightbulb } from 'lucide-react'
import { AnimatePresence, motion } from 'motion/react' import { motion } from 'motion/react'
import React, { useEffect, useMemo, useState } from 'react' import React, { useEffect, useMemo, useState } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
@ -25,15 +25,15 @@ const ThinkingEffect: React.FC<Props> = ({ isThinking, thinkingTimeText, content
} }
}, [content, isThinking, messages]) }, [content, isThinking, messages])
const lineHeight = 16 const LINE_HEIGHT = 14
const containerHeight = useMemo(() => { const containerHeight = useMemo(() => {
if (expanded) return lineHeight * 3 if (expanded || messages.length < 2) return 38
return Math.min(80, Math.max(messages.length + 2, 3) * lineHeight) return Math.min(68, Math.max(messages.length + 1, 2) * LINE_HEIGHT + 10)
}, [expanded, messages.length]) }, [expanded, messages.length])
return ( return (
<ThinkingContainer style={{ height: containerHeight }} className={expanded ? 'expanded' : ''}> <ThinkingContainer style={{ height: containerHeight }} className={expanded ? 'expanded' : ''}>
<LoadingContainer className={expanded || !messages.length ? 'expanded' : ''}> <LoadingContainer>
<motion.div variants={lightbulbVariants} animate={isThinking ? 'active' : 'idle'} initial="idle"> <motion.div variants={lightbulbVariants} animate={isThinking ? 'active' : 'idle'} initial="idle">
<Lightbulb size={expanded || !messages.length ? 20 : 30} style={{ transition: 'width,height, 150ms' }} /> <Lightbulb size={expanded || !messages.length ? 20 : 30} style={{ transition: 'width,height, 150ms' }} />
</motion.div> </motion.div>
@ -44,31 +44,26 @@ const ThinkingEffect: React.FC<Props> = ({ isThinking, thinkingTimeText, content
{!expanded && ( {!expanded && (
<Content> <Content>
<AnimatePresence> <Messages
style={{
height: messages.length * LINE_HEIGHT
}}
initial={{
y: -2
}}
animate={{
y: -messages.length * LINE_HEIGHT - 2
}}
transition={{
duration: 0.15,
ease: 'linear'
}}>
{messages.map((message, index) => { {messages.map((message, index) => {
const finalY = containerHeight - (messages.length - index) * lineHeight - 4
if (index < messages.length - 5) return null if (index < messages.length - 5) return null
return ( return <Message key={index}>{message}</Message>
<ContentLineMotion
key={index}
initial={{
y: index === messages.length - 1 ? containerHeight : finalY + lineHeight,
height: lineHeight
}}
animate={{
y: finalY
}}
transition={{
duration: 0.15,
ease: 'linear'
}}>
{message}
</ContentLineMotion>
)
})} })}
</AnimatePresence> </Messages>
</Content> </Content>
)} )}
</TextContainer> </TextContainer>
@ -99,17 +94,18 @@ const Title = styled.div`
position: absolute; position: absolute;
inset: 0 0 auto 0; inset: 0 0 auto 0;
font-size: 14px; font-size: 14px;
line-height: 14px;
font-weight: 500; font-weight: 500;
padding: 4px 0 30px; padding: 6px 0;
z-index: 99; z-index: 99;
transition: padding-top 150ms; transition: padding-top 150ms;
&.expanded { &.expanded {
padding-top: 14px; padding-top: 12px;
} }
` `
const LoadingContainer = styled.div` const LoadingContainer = styled.div`
width: 60px; width: 50px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@ -123,9 +119,6 @@ const LoadingContainer = styled.div`
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
&.expanded {
width: 40px;
}
` `
const TextContainer = styled.div` const TextContainer = styled.div`
@ -135,7 +128,7 @@ const TextContainer = styled.div`
position: relative; position: relative;
` `
const Content = styled(motion.div)` const Content = styled.div`
width: 100%; width: 100%;
height: 100%; height: 100%;
mask: linear-gradient( mask: linear-gradient(
@ -146,17 +139,26 @@ const Content = styled(motion.div)`
rgb(0 0 0 / 100%) 90%, rgb(0 0 0 / 100%) 90%,
rgb(0 0 0 / 100%) 100% rgb(0 0 0 / 100%) 100%
); );
position: relative;
` `
const ContentLineMotion = styled(motion.div)` const Messages = styled(motion.div)`
width: 100%; width: 100%;
line-height: 16px; position: absolute;
font-size: 12px; top: 100%;
display: flex;
flex-direction: column;
justify-content: flex-end;
`
const Message = styled.div`
width: 100%;
line-height: 14px;
font-size: 11px;
color: var(--color-text-2); color: var(--color-text-2);
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
position: absolute;
` `
const ArrowContainer = styled.div` const ArrowContainer = styled.div`

View File

@ -136,7 +136,6 @@ const ThinkingTimeSeconds = memo(
) )
const CollapseContainer = styled(Collapse)` const CollapseContainer = styled(Collapse)`
margin-top: 15px;
margin-bottom: 15px; margin-bottom: 15px;
.ant-collapse-header { .ant-collapse-header {
padding: 0 !important; padding: 0 !important;

View File

@ -2,7 +2,6 @@
exports[`ThinkingBlock > basic rendering > should match snapshot 1`] = ` exports[`ThinkingBlock > basic rendering > should match snapshot 1`] = `
.c0 { .c0 {
margin-top: 15px;
margin-bottom: 15px; margin-bottom: 15px;
} }

View File

@ -4,6 +4,7 @@ import MessageContent from '@renderer/pages/home/Messages/MessageContent'
import MessageErrorBoundary from '@renderer/pages/home/Messages/MessageErrorBoundary' import MessageErrorBoundary from '@renderer/pages/home/Messages/MessageErrorBoundary'
// import { LegacyMessage } from '@renderer/types' // import { LegacyMessage } from '@renderer/types'
import type { Message } from '@renderer/types/newMessage' import type { Message } from '@renderer/types/newMessage'
import { classNames } from '@renderer/utils'
import { FC, memo, useRef } from 'react' import { FC, memo, useRef } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
@ -21,7 +22,6 @@ const MessageItem: FC<Props> = ({ message, index, total, route }) => {
// const [message, setMessage] = useState(_message) // const [message, setMessage] = useState(_message)
// const [bl, setTextBlock] = useState<MainTextMessageBlock | null>(null) // const [bl, setTextBlock] = useState<MainTextMessageBlock | null>(null)
// const model = useModel(getMessageModelId(message)) // const model = useModel(getMessageModelId(message))
const isBubbleStyle = true
const { messageFont, fontSize } = useSettings() const { messageFont, fontSize } = useSettings()
const messageContainerRef = useRef<HTMLDivElement>(null) const messageContainerRef = useRef<HTMLDivElement>(null)
@ -39,14 +39,18 @@ const MessageItem: FC<Props> = ({ message, index, total, route }) => {
<MessageContainer <MessageContainer
key={message.id} key={message.id}
ref={messageContainerRef} ref={messageContainerRef}
style={{ ...(isBubbleStyle ? { alignItems: isAssistantMessage ? 'start' : 'end' } : {}), maxWidth }}> className={classNames({
message: true,
'message-assistant': isAssistantMessage,
'message-user': !isAssistantMessage
})}
style={{ maxWidth }}>
<MessageContentContainer <MessageContentContainer
className="message-content-container" className="message-content-container"
style={{ style={{
fontFamily: messageFont === 'serif' ? 'var(--font-family-serif)' : 'var(--font-family)', fontFamily: messageFont === 'serif' ? 'var(--font-family-serif)' : 'var(--font-family)',
fontSize, fontSize,
background: messageBackground, background: messageBackground
...(isAssistantMessage ? { paddingLeft: 5, paddingRight: 5 } : {})
}}> }}>
<MessageErrorBoundary> <MessageErrorBoundary>
<MessageContent message={message} /> <MessageContent message={message} />