refactor: update styles and layout in markdown and message components

- Removed unnecessary letter and word spacing in markdown styles.
- Adjusted padding in Inputbar for improved layout.
- Modified margin properties in CitationsList and Message components for consistency.
- Enhanced MessageHeader logic to conditionally hide based on message type.
- Updated icon sizes in MessageMenubar for better alignment.
- Added margin adjustments in ThinkingBlock for improved spacing.
This commit is contained in:
kangfenmao 2025-07-11 11:07:35 +08:00
parent 8340922263
commit 5b9ff3053b
9 changed files with 42 additions and 71 deletions

View File

@ -3,8 +3,6 @@
line-height: 1.6; line-height: 1.6;
user-select: text; user-select: text;
word-break: break-word; word-break: break-word;
letter-spacing: 0.02em;
word-spacing: 0.05em;
h1:first-child, h1:first-child,
h2:first-child, h2:first-child,
@ -59,7 +57,7 @@
p { p {
margin: 1.3em 0; margin: 1.3em 0;
white-space: pre-wrap; white-space: pre-wrap;
line-height: 2; line-height: 1.6;
&:last-child { &:last-child {
margin-bottom: 5px; margin-bottom: 5px;
@ -87,7 +85,7 @@
li { li {
margin-bottom: 0.5em; margin-bottom: 0.5em;
pre { pre {
margin: 1.5em 0; margin: 1.5em 0 !important;
} }
&::marker { &::marker {
color: var(--color-text-3); color: var(--color-text-3);
@ -201,6 +199,7 @@
img { img {
max-width: 100%; max-width: 100%;
height: auto; height: auto;
margin: 10px 0;
} }
a, a,

View File

@ -188,12 +188,6 @@ const HtmlArtifactsCard: FC<Props> = ({ html }) => {
<span>HTML</span> <span>HTML</span>
</TypeBadge> </TypeBadge>
</TitleSection> </TitleSection>
{isStreaming && (
<StreamingIndicator>
<ClipLoader size={16} color="currentColor" />
<StreamingText>{t('html_artifacts.generating')}</StreamingText>
</StreamingIndicator>
)}
</Header> </Header>
<Content> <Content>
{isStreaming && !hasContent ? ( {isStreaming && !hasContent ? (
@ -336,42 +330,16 @@ const TypeBadge = styled.div`
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
padding: 4px 8px; padding: 3px 6px;
background: var(--color-background-mute); background: var(--color-background-mute);
border: 1px solid var(--color-border); border: 1px solid var(--color-border);
border-radius: 6px; border-radius: 6px;
font-size: 11px; font-size: 10px;
font-weight: 500; font-weight: 500;
color: var(--color-text-secondary); color: var(--color-text-secondary);
width: fit-content; width: fit-content;
` `
const StreamingIndicator = styled.div`
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
background: var(--color-status-warning);
border: 1px solid var(--color-status-warning);
border-radius: 8px;
color: var(--color-text);
font-size: 12px;
opacity: 0.9;
[theme-mode='light'] & {
background: #fef3c7;
border-color: #fbbf24;
color: #92400e;
}
`
const StreamingText = styled.div`
display: flex;
align-items: center;
gap: 4px;
font-weight: 500;
`
const Content = styled.div` const Content = styled.div`
padding: 0; padding: 0;
background: var(--color-background); background: var(--color-background);

View File

@ -955,7 +955,7 @@ const Container = styled.div`
flex-direction: column; flex-direction: column;
position: relative; position: relative;
z-index: 2; z-index: 2;
padding: 0 20px 18px 20px; padding: 0 24px 18px 24px;
` `
const InputBarContainer = styled.div` const InputBarContainer = styled.div`

View File

@ -151,6 +151,7 @@ const ThinkingTimeSeconds = memo(
const CollapseContainer = styled(Collapse)` const CollapseContainer = styled(Collapse)`
margin: 15px 0; margin: 15px 0;
margin-top: 5px;
` `
const MessageTitleLabel = styled.div` const MessageTitleLabel = styled.div`

View File

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

View File

@ -188,7 +188,7 @@ const OpenButton = styled(Button)`
display: flex; display: flex;
align-items: center; align-items: center;
padding: 3px 8px; padding: 3px 8px;
margin: 8px 0; margin-bottom: 8px;
align-self: flex-start; align-self: flex-start;
font-size: 12px; font-size: 12px;
background-color: var(--color-background-soft); background-color: var(--color-background-soft);

View File

@ -127,8 +127,6 @@ const MessageItem: FC<Props> = ({
) )
} }
const showHeader = messageStyle === 'plain' || isAssistantMessage
return ( return (
<MessageContainer <MessageContainer
key={message.id} key={message.id}
@ -138,15 +136,7 @@ const MessageItem: FC<Props> = ({
'message-user': !isAssistantMessage 'message-user': !isAssistantMessage
})} })}
ref={messageContainerRef}> ref={messageContainerRef}>
{showHeader && ( <MessageHeader message={message} assistant={assistant} model={model} key={getModelUniqId(model)} topic={topic} />
<MessageHeader
message={message}
assistant={assistant}
model={model}
key={getModelUniqId(model)}
topic={topic}
/>
)}
{isEditing && ( {isEditing && (
<MessageEditor <MessageEditor
message={message} message={message}
@ -170,7 +160,7 @@ const MessageItem: FC<Props> = ({
</MessageErrorBoundary> </MessageErrorBoundary>
</MessageContentContainer> </MessageContentContainer>
{showMenubar && ( {showMenubar && (
<MessageFooter className="MessageFooter" $isLastMessage={isLastMessage}> <MessageFooter className="MessageFooter" $isLastMessage={isLastMessage} $messageStyle={messageStyle}>
<MessageMenubar <MessageMenubar
message={message} message={message}
assistant={assistant} assistant={assistant}
@ -199,7 +189,7 @@ const MessageContainer = styled.div`
transition: background-color 0.3s ease; transition: background-color 0.3s ease;
transform: translateZ(0); transform: translateZ(0);
will-change: transform; will-change: transform;
padding: 10px 10px 0 10px; padding: 10px;
border-radius: 10px; border-radius: 10px;
&.message-highlight { &.message-highlight {
background-color: var(--color-primary-mute); background-color: var(--color-primary-mute);
@ -227,14 +217,15 @@ const MessageContentContainer = styled(Scrollbar)`
overflow-y: auto; overflow-y: auto;
` `
const MessageFooter = styled.div<{ $isLastMessage: boolean }>` const MessageFooter = styled.div<{ $isLastMessage: boolean; $messageStyle: 'plain' | 'bubble' }>`
display: flex; display: flex;
flex-direction: ${({ $isLastMessage }) => ($isLastMessage ? 'row-reverse' : 'row')}; flex-direction: ${({ $isLastMessage, $messageStyle }) =>
$isLastMessage && $messageStyle === 'plain' ? 'row-reverse' : 'row'};
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 10px; gap: 10px;
margin-left: 46px; margin-left: 46px;
margin-top: 2px; margin-top: 8px;
` `
const NewContextMessage = styled.div` const NewContextMessage = styled.div`

View File

@ -57,6 +57,7 @@ const MessageHeader: FC<Props> = memo(({ assistant, model, message, topic }) =>
}, [message, model, t, userName]) }, [message, model, t, userName])
const isAssistantMessage = message.role === 'assistant' const isAssistantMessage = message.role === 'assistant'
const isUserMessage = message.role === 'user'
const showMinappIcon = sidebarIcons.visible.includes('minapp') const showMinappIcon = sidebarIcons.visible.includes('minapp')
const avatarName = useMemo(() => firstLetter(assistant?.name).toUpperCase(), [assistant?.name]) const avatarName = useMemo(() => firstLetter(assistant?.name).toUpperCase(), [assistant?.name])
@ -68,6 +69,12 @@ const MessageHeader: FC<Props> = memo(({ assistant, model, message, topic }) =>
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [model?.provider, showMinappIcon]) }, [model?.provider, showMinappIcon])
const hideHeader = isBubbleStyle ? isUserMessage && !isMultiSelectMode : false
if (hideHeader) {
return null
}
return ( return (
<Container className="message-header"> <Container className="message-header">
{isAssistantMessage ? ( {isAssistantMessage ? (

View File

@ -188,7 +188,7 @@ const MessageMenubar: FC<Props> = (props) => {
{ {
label: t('common.edit'), label: t('common.edit'),
key: 'edit', key: 'edit',
icon: <FilePenLine size={16} />, icon: <FilePenLine size={15} />,
onClick: onEdit onClick: onEdit
} }
] ]
@ -196,13 +196,13 @@ const MessageMenubar: FC<Props> = (props) => {
{ {
label: t('chat.message.new.branch'), label: t('chat.message.new.branch'),
key: 'new-branch', key: 'new-branch',
icon: <Split size={16} />, icon: <Split size={15} />,
onClick: onNewBranch onClick: onNewBranch
}, },
{ {
label: t('chat.multiple.select'), label: t('chat.multiple.select'),
key: 'multi-select', key: 'multi-select',
icon: <ListChecks size={16} />, icon: <ListChecks size={15} />,
onClick: () => { onClick: () => {
toggleMultiSelectMode(true) toggleMultiSelectMode(true)
} }
@ -210,7 +210,7 @@ const MessageMenubar: FC<Props> = (props) => {
{ {
label: t('chat.save'), label: t('chat.save'),
key: 'save', key: 'save',
icon: <Save size={16} color="var(--color-icon)" style={{ marginTop: 3 }} />, icon: <Save size={15} color="var(--color-icon)" style={{ marginTop: 3 }} />,
children: [ children: [
{ {
label: t('chat.save.file.title'), label: t('chat.save.file.title'),
@ -232,7 +232,7 @@ const MessageMenubar: FC<Props> = (props) => {
{ {
label: t('chat.topics.export.title'), label: t('chat.topics.export.title'),
key: 'export', key: 'export',
icon: <Share size={16} color="var(--color-icon)" style={{ marginTop: 3 }} />, icon: <Share size={15} color="var(--color-icon)" style={{ marginTop: 3 }} />,
children: [ children: [
exportMenuOptions.plain_text && { exportMenuOptions.plain_text && {
label: t('chat.topics.copy.plain_text'), label: t('chat.topics.copy.plain_text'),
@ -413,13 +413,14 @@ const MessageMenubar: FC<Props> = (props) => {
}, [message]) }, [message])
const softHoverBg = isBubbleStyle && !isLastMessage const softHoverBg = isBubbleStyle && !isLastMessage
const showMessageTokens = !isBubbleStyle
const showMessageTokens = isBubbleStyle ? isAssistantMessage : true const isUserBubbleStyleMessage = isBubbleStyle && isUserMessage
return ( return (
<> <>
{showMessageTokens && <MessageTokens message={message} />} {showMessageTokens && <MessageTokens message={message} />}
<MenusBar className={classNames({ menubar: true, show: isLastMessage })}> <MenusBar
className={classNames({ menubar: true, show: isLastMessage, 'user-bubble-style': isUserBubbleStyleMessage })}>
{message.role === 'user' && ( {message.role === 'user' && (
<Tooltip title={t('common.regenerate')} mouseEnterDelay={0.8}> <Tooltip title={t('common.regenerate')} mouseEnterDelay={0.8}>
<ActionButton <ActionButton
@ -439,7 +440,7 @@ const MessageMenubar: FC<Props> = (props) => {
)} )}
<Tooltip title={t('common.copy')} mouseEnterDelay={0.8}> <Tooltip title={t('common.copy')} mouseEnterDelay={0.8}>
<ActionButton className="message-action-button" onClick={onCopy} $softHoverBg={softHoverBg}> <ActionButton className="message-action-button" onClick={onCopy} $softHoverBg={softHoverBg}>
{!copied && <Copy size={16} />} {!copied && <Copy size={15} />}
{copied && <CheckOutlined style={{ color: 'var(--color-primary)' }} />} {copied && <CheckOutlined style={{ color: 'var(--color-primary)' }} />}
</ActionButton> </ActionButton>
</Tooltip> </Tooltip>
@ -456,7 +457,7 @@ const MessageMenubar: FC<Props> = (props) => {
open={showRegenerateTooltip} open={showRegenerateTooltip}
onOpenChange={setShowRegenerateTooltip}> onOpenChange={setShowRegenerateTooltip}>
<ActionButton className="message-action-button" $softHoverBg={softHoverBg}> <ActionButton className="message-action-button" $softHoverBg={softHoverBg}>
<RefreshCw size={16} /> <RefreshCw size={15} />
</ActionButton> </ActionButton>
</Tooltip> </Tooltip>
</Popconfirm> </Popconfirm>
@ -464,7 +465,7 @@ const MessageMenubar: FC<Props> = (props) => {
{isAssistantMessage && ( {isAssistantMessage && (
<Tooltip title={t('message.mention.title')} mouseEnterDelay={0.8}> <Tooltip title={t('message.mention.title')} mouseEnterDelay={0.8}>
<ActionButton className="message-action-button" onClick={onMentionModel} $softHoverBg={softHoverBg}> <ActionButton className="message-action-button" onClick={onMentionModel} $softHoverBg={softHoverBg}>
<AtSign size={16} /> <AtSign size={15} />
</ActionButton> </ActionButton>
</Tooltip> </Tooltip>
)} )}
@ -538,7 +539,7 @@ const MessageMenubar: FC<Props> = (props) => {
className="message-action-button" className="message-action-button"
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
$softHoverBg={softHoverBg}> $softHoverBg={softHoverBg}>
<Languages size={16} /> <Languages size={15} />
</ActionButton> </ActionButton>
</Tooltip> </Tooltip>
</Dropdown> </Dropdown>
@ -549,7 +550,7 @@ const MessageMenubar: FC<Props> = (props) => {
{message.useful ? ( {message.useful ? (
<ThumbsUp size={17.5} fill="var(--color-primary)" strokeWidth={0} /> <ThumbsUp size={17.5} fill="var(--color-primary)" strokeWidth={0} />
) : ( ) : (
<ThumbsUp size={16} /> <ThumbsUp size={15} />
)} )}
</ActionButton> </ActionButton>
</Tooltip> </Tooltip>
@ -569,7 +570,7 @@ const MessageMenubar: FC<Props> = (props) => {
mouseEnterDelay={1} mouseEnterDelay={1}
open={showDeleteTooltip} open={showDeleteTooltip}
onOpenChange={setShowDeleteTooltip}> onOpenChange={setShowDeleteTooltip}>
<Trash size={16} /> <Trash size={15} />
</Tooltip> </Tooltip>
</ActionButton> </ActionButton>
</Popconfirm> </Popconfirm>
@ -597,7 +598,10 @@ const MenusBar = styled.div`
justify-content: flex-end; justify-content: flex-end;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
margin-top: 5px;
&.user-bubble-style {
margin-top: 5px;
}
` `
const ActionButton = styled.div<{ $softHoverBg?: boolean }>` const ActionButton = styled.div<{ $softHoverBg?: boolean }>`