mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-11 08:19:01 +08:00
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:
parent
8340922263
commit
5b9ff3053b
@ -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,
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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`
|
||||||
|
|||||||
@ -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`
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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`
|
||||||
|
|||||||
@ -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 ? (
|
||||||
|
|||||||
@ -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 }>`
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user