refactor(Messages): update message styling and structure for improved clarity

- Simplified the message header and footer components by removing unnecessary props and logic.
- Adjusted the message container styles for better alignment and spacing.
- Enhanced the message tokens display logic and corrected the component name for consistency.
- Removed unused translation keys related to token usage from multiple language files to streamline localization.
This commit is contained in:
kangfenmao 2025-07-09 21:41:58 +08:00
parent 8c6684cbdf
commit 1d854c232e
15 changed files with 258 additions and 264 deletions

View File

@ -139,7 +139,7 @@ ul {
}
}
.message-content-container {
border-radius: 10px 0 10px 10px;
border-radius: 10px;
padding: 10px 16px 10px 16px;
background-color: var(--chat-background-user);
align-self: self-end;

View File

@ -55,6 +55,7 @@
p {
margin: 1em 0;
white-space: pre-wrap;
line-height: 2em;
&:last-child {
margin-bottom: 5px;
@ -108,6 +109,7 @@
li code {
background: var(--color-background-mute);
padding: 3px 5px;
margin: 0 2px;
border-radius: 5px;
word-break: keep-all;
white-space: pre;

View File

@ -1890,7 +1890,6 @@
"messages.navigation.none": "None",
"messages.prompt": "Show prompt",
"messages.title": "Message Settings",
"messages.tokens": "Show token usage",
"messages.use_serif_font": "Use serif font",
"mineru.api_key": "Mineru now offers a daily free quota of 500 pages, and you do not need to enter a key.",
"miniapps": {

View File

@ -1890,7 +1890,6 @@
"messages.navigation.none": "表示しない",
"messages.prompt": "プロンプト表示",
"messages.title": "メッセージ設定",
"messages.tokens": "トークン使用量を表示",
"messages.use_serif_font": "セリフフォントを使用",
"mineru.api_key": "Mineruでは現在、1日500ページの無料クォータを提供しており、キーを入力する必要はありません。",
"miniapps": {

View File

@ -1890,7 +1890,6 @@
"messages.navigation.none": "Не показывать",
"messages.prompt": "Показывать подсказки",
"messages.title": "Настройки сообщений",
"messages.tokens": "Показать использование токенов",
"messages.use_serif_font": "Использовать serif шрифт",
"mineru.api_key": "Mineru теперь предлагает ежедневную бесплатную квоту в 500 страниц, и вам не нужно вводить ключ.",
"miniapps": {

View File

@ -1890,7 +1890,6 @@
"messages.navigation.none": "不显示",
"messages.prompt": "显示提示词",
"messages.title": "消息设置",
"messages.tokens": "显示 Token 用量",
"messages.use_serif_font": "使用衬线字体",
"mineru.api_key": "MinerU现在提供每日500页的免费额度您不需要填写密钥。",
"miniapps": {

View File

@ -1890,7 +1890,6 @@
"messages.navigation.none": "不顯示",
"messages.prompt": "提示詞顯示",
"messages.title": "訊息設定",
"messages.tokens": "Token 用量顯示",
"messages.use_serif_font": "使用襯線字型",
"mineru.api_key": "Mineru 現在每天提供 500 頁的免費配額,且無需輸入金鑰。",
"miniapps": {

View File

@ -47,7 +47,7 @@ const MessageItem: FC<Props> = ({
const { t } = useTranslation()
const { assistant, setModel } = useAssistant(message.assistantId)
const model = useModel(getMessageModelId(message), message.model?.provider) || message.model
const { messageFont, fontSize } = useSettings()
const { messageFont, fontSize, messageStyle } = useSettings()
const { editMessageBlocks, resendUserMessageWithEdit, editMessage } = useMessageOperations(topic)
const messageContainerRef = useRef<HTMLDivElement>(null)
const { editingMessageId, stopEditing } = useMessageEditing()
@ -127,6 +127,8 @@ const MessageItem: FC<Props> = ({
)
}
const showHeader = messageStyle === 'plain' || isAssistantMessage
return (
<MessageContainer
key={message.id}
@ -136,14 +138,15 @@ const MessageItem: FC<Props> = ({
'message-user': !isAssistantMessage
})}
ref={messageContainerRef}>
<MessageHeader
message={message}
assistant={assistant}
model={model}
key={getModelUniqId(model)}
index={index}
topic={topic}
/>
{showHeader && (
<MessageHeader
message={message}
assistant={assistant}
model={model}
key={getModelUniqId(model)}
topic={topic}
/>
)}
{isEditing && (
<MessageEditor
message={message}
@ -167,7 +170,7 @@ const MessageItem: FC<Props> = ({
</MessageErrorBoundary>
</MessageContentContainer>
{showMenubar && (
<MessageFooter className="MessageFooter">
<MessageFooter className="MessageFooter" $isLastMessage={isLastMessage}>
<MessageMenubar
message={message}
assistant={assistant}
@ -224,12 +227,12 @@ const MessageContentContainer = styled(Scrollbar)`
overflow-y: auto;
`
const MessageFooter = styled.div`
const MessageFooter = styled.div<{ $isLastMessage: boolean }>`
display: flex;
flex-direction: row;
justify-content: space-between;
flex-direction: ${({ $isLastMessage }) => ($isLastMessage ? 'row-reverse' : 'row')};
align-items: center;
gap: 20px;
justify-content: space-between;
gap: 10px;
margin-left: 46px;
margin-top: 2px;
`

View File

@ -75,14 +75,14 @@ const MessageBlockEditor: FC<Props> = ({ message, topicId, onSave, onResend, onC
supportExts,
setFiles,
undefined, // 不需要setText
pasteLongTextAsFile,
false, // 不需要 pasteLongTextAsFile
pasteLongTextThreshold,
undefined, // 不需要text
resizeTextArea,
t
)
},
[model, pasteLongTextAsFile, pasteLongTextThreshold, resizeTextArea, supportExts, t]
[model, pasteLongTextThreshold, resizeTextArea, supportExts, t]
)
// 添加全局粘贴事件处理
@ -256,71 +256,72 @@ const MessageBlockEditor: FC<Props> = ({ message, topicId, onSave, onResend, onC
}, [couldAddImageFile, couldAddTextFile])
return (
<EditorContainer className="message-editor" onDragOver={(e) => e.preventDefault()} onDrop={handleDrop}>
{editedBlocks
.filter((block) => block.type === MessageBlockType.MAIN_TEXT)
.map((block) => (
<Textarea
className={classNames('editing-message', isFileDragging && 'file-dragging')}
key={block.id}
ref={textareaRef}
variant="borderless"
value={block.content}
onChange={(e) => {
handleTextChange(block.id, e.target.value)
resizeTextArea()
}}
onKeyDown={(e) => handleKeyDown(e, block.id)}
autoFocus
spellCheck={enableSpellCheck}
onPaste={(e) => onPaste(e.nativeEvent)}
onFocus={() => {
// 记录当前聚焦的组件
PasteService.setLastFocusedComponent('messageEditor')
}}
onContextMenu={(e) => {
// 阻止事件冒泡,避免触发全局的 Electron contextMenu
e.stopPropagation()
}}
style={{
fontSize,
padding: '0px 15px 8px 15px'
}}>
<TranslateButton onTranslated={onTranslated} />
</Textarea>
))}
{(editedBlocks.some((block) => block.type === MessageBlockType.FILE || block.type === MessageBlockType.IMAGE) ||
files.length > 0) && (
<FileBlocksContainer>
{editedBlocks
.filter((block) => block.type === MessageBlockType.FILE || block.type === MessageBlockType.IMAGE)
.map(
(block) =>
block.file && (
<CustomTag
key={block.id}
icon={getFileIcon(block.file.ext)}
color="#37a5aa"
closable
onClose={() => handleFileRemove(block.id)}>
<FileNameRender file={block.file} />
</CustomTag>
)
)}
{files.map((file) => (
<CustomTag
key={file.id}
icon={getFileIcon(file.ext)}
color="#37a5aa"
closable
onClose={() => setFiles((prevFiles) => prevFiles.filter((f) => f.id !== file.id))}>
<FileNameRender file={file} />
</CustomTag>
<>
<EditorContainer className="message-editor" onDragOver={(e) => e.preventDefault()} onDrop={handleDrop}>
{editedBlocks
.filter((block) => block.type === MessageBlockType.MAIN_TEXT)
.map((block) => (
<Textarea
className={classNames('editing-message', isFileDragging && 'file-dragging')}
key={block.id}
ref={textareaRef}
variant="borderless"
value={block.content}
onChange={(e) => {
handleTextChange(block.id, e.target.value)
resizeTextArea()
}}
onKeyDown={(e) => handleKeyDown(e, block.id)}
autoFocus
spellCheck={enableSpellCheck}
onPaste={(e) => onPaste(e.nativeEvent)}
onFocus={() => {
// 记录当前聚焦的组件
PasteService.setLastFocusedComponent('messageEditor')
}}
onContextMenu={(e) => {
// 阻止事件冒泡,避免触发全局的 Electron contextMenu
e.stopPropagation()
}}
style={{
fontSize,
padding: '0px 15px 8px 15px'
}}>
<TranslateButton onTranslated={onTranslated} />
</Textarea>
))}
</FileBlocksContainer>
)}
{(editedBlocks.some((block) => block.type === MessageBlockType.FILE || block.type === MessageBlockType.IMAGE) ||
files.length > 0) && (
<FileBlocksContainer>
{editedBlocks
.filter((block) => block.type === MessageBlockType.FILE || block.type === MessageBlockType.IMAGE)
.map(
(block) =>
block.file && (
<CustomTag
key={block.id}
icon={getFileIcon(block.file.ext)}
color="#37a5aa"
closable
onClose={() => handleFileRemove(block.id)}>
<FileNameRender file={block.file} />
</CustomTag>
)
)}
{files.map((file) => (
<CustomTag
key={file.id}
icon={getFileIcon(file.ext)}
color="#37a5aa"
closable
onClose={() => setFiles((prevFiles) => prevFiles.filter((f) => f.id !== file.id))}>
<FileNameRender file={file} />
</CustomTag>
))}
</FileBlocksContainer>
)}
</EditorContainer>
<ActionBar>
<ActionBarLeft>
{isUserMessage && (
@ -355,17 +356,17 @@ const MessageBlockEditor: FC<Props> = ({ message, topicId, onSave, onResend, onC
)}
</ActionBarRight>
</ActionBar>
</EditorContainer>
</>
)
}
const EditorContainer = styled.div`
padding: 8px 0;
padding: 18px 0;
padding-bottom: 5px;
border: 0.5px solid var(--color-border);
transition: all 0.2s ease;
border-radius: 15px;
margin-top: 5px;
margin-bottom: 10px;
margin-top: 18px;
background-color: var(--color-background-opacity);
width: 100%;

View File

@ -18,13 +18,10 @@ import { FC, memo, useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import MessageTokens from './MessageTokens'
interface Props {
message: Message
assistant: Assistant
model?: Model
index: number | undefined
topic: Topic
}
@ -33,7 +30,7 @@ const getAvatarSource = (isLocalAi: boolean, modelId: string | undefined) => {
return modelId ? getModelLogo(modelId) : undefined
}
const MessageHeader: FC<Props> = memo(({ assistant, model, message, index, topic }) => {
const MessageHeader: FC<Props> = memo(({ assistant, model, message, topic }) => {
const avatar = useAvatar()
const { theme } = useTheme()
const { userName, sidebarIcons } = useSettings()
@ -61,11 +58,9 @@ const MessageHeader: FC<Props> = memo(({ assistant, model, message, index, topic
const isAssistantMessage = message.role === 'assistant'
const showMinappIcon = sidebarIcons.visible.includes('minapp')
const { showTokens } = useSettings()
const avatarName = useMemo(() => firstLetter(assistant?.name).toUpperCase(), [assistant?.name])
const username = useMemo(() => removeLeadingEmoji(getUserName()), [getUserName])
const isLastMessage = index === 0
const showMiniApp = useCallback(() => {
showMinappIcon && model?.provider && openMinappById(model.provider)
@ -110,8 +105,6 @@ const MessageHeader: FC<Props> = memo(({ assistant, model, message, index, topic
</UserName>
<InfoWrap className="message-header-info-wrap">
<MessageTime>{dayjs(message?.updatedAt ?? message.createdAt).format('MM/DD HH:mm')}</MessageTime>
{showTokens && <DividerContainer style={{ color: 'var(--color-text-3)' }}> | </DividerContainer>}
<MessageTokens message={message} isLastMessage={isLastMessage} />
</InfoWrap>
</UserWrap>
{isMultiSelectMode && (
@ -149,12 +142,6 @@ const InfoWrap = styled.div`
gap: 4px;
`
const DividerContainer = styled.div`
font-size: 10px;
color: var(--color-text-3);
margin: 0 2px;
`
const UserName = styled.div<{ isBubbleStyle?: boolean; theme?: string }>`
font-size: 14px;
font-weight: 600;

View File

@ -49,6 +49,8 @@ import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
import styled from 'styled-components'
import MessageTokens from './MessageTokens'
interface Props {
message: Message
assistant: Assistant
@ -398,172 +400,180 @@ const MessageMenubar: FC<Props> = (props) => {
const softHoverBg = isBubbleStyle && !isLastMessage
const showMessageTokens = isBubbleStyle ? isAssistantMessage : true
return (
<MenusBar className={classNames({ menubar: true, show: isLastMessage })}>
{message.role === 'user' && (
<Tooltip title={t('common.regenerate')} mouseEnterDelay={0.8}>
<ActionButton
className="message-action-button"
onClick={() => handleResendUserMessage()}
$softHoverBg={isBubbleStyle}>
<SyncOutlined />
</ActionButton>
</Tooltip>
)}
{message.role === 'user' && (
<Tooltip title={t('common.edit')} mouseEnterDelay={0.8}>
<ActionButton className="message-action-button" onClick={onEdit} $softHoverBg={softHoverBg}>
<EditOutlined />
</ActionButton>
</Tooltip>
)}
<Tooltip title={t('common.copy')} mouseEnterDelay={0.8}>
<ActionButton className="message-action-button" onClick={onCopy} $softHoverBg={softHoverBg}>
{!copied && <Copy size={16} />}
{copied && <CheckOutlined style={{ color: 'var(--color-primary)' }} />}
</ActionButton>
</Tooltip>
{isAssistantMessage && (
<Popconfirm
title={t('message.regenerate.confirm')}
okButtonProps={{ danger: true }}
icon={<QuestionCircleOutlined style={{ color: 'red' }} />}
onConfirm={onRegenerate}
onOpenChange={(open) => open && setShowRegenerateTooltip(false)}>
<Tooltip
title={t('common.regenerate')}
mouseEnterDelay={0.8}
open={showRegenerateTooltip}
onOpenChange={setShowRegenerateTooltip}>
<ActionButton className="message-action-button" $softHoverBg={softHoverBg}>
<RefreshCw size={16} />
<>
{showMessageTokens && <MessageTokens message={message} />}
<MenusBar className={classNames({ menubar: true, show: isLastMessage })}>
{message.role === 'user' && (
<Tooltip title={t('common.regenerate')} mouseEnterDelay={0.8}>
<ActionButton
className="message-action-button"
onClick={() => handleResendUserMessage()}
$softHoverBg={isBubbleStyle}>
<SyncOutlined />
</ActionButton>
</Tooltip>
</Popconfirm>
)}
{isAssistantMessage && (
<Tooltip title={t('message.mention.title')} mouseEnterDelay={0.8}>
<ActionButton className="message-action-button" onClick={onMentionModel} $softHoverBg={softHoverBg}>
<AtSign size={16} />
)}
{message.role === 'user' && (
<Tooltip title={t('common.edit')} mouseEnterDelay={0.8}>
<ActionButton className="message-action-button" onClick={onEdit} $softHoverBg={softHoverBg}>
<EditOutlined />
</ActionButton>
</Tooltip>
)}
<Tooltip title={t('common.copy')} mouseEnterDelay={0.8}>
<ActionButton className="message-action-button" onClick={onCopy} $softHoverBg={softHoverBg}>
{!copied && <Copy size={16} />}
{copied && <CheckOutlined style={{ color: 'var(--color-primary)' }} />}
</ActionButton>
</Tooltip>
)}
{!isUserMessage && (
<Dropdown
menu={{
style: {
maxHeight: 250,
overflowY: 'auto',
backgroundClip: 'border-box'
},
items: [
...translateLanguageOptions.map((item) => ({
label: item.emoji + ' ' + item.label(),
key: item.langCode,
onClick: () => handleTranslate(item)
})),
...(hasTranslationBlocks
? [
{ type: 'divider' as const },
{
label: '📋 ' + t('common.copy'),
key: 'translate-copy',
onClick: () => {
const translationBlocks = message.blocks
.map((blockId) => blockEntities[blockId])
.filter((block) => block?.type === 'translation')
{isAssistantMessage && (
<Popconfirm
title={t('message.regenerate.confirm')}
okButtonProps={{ danger: true }}
icon={<QuestionCircleOutlined style={{ color: 'red' }} />}
onConfirm={onRegenerate}
onOpenChange={(open) => open && setShowRegenerateTooltip(false)}>
<Tooltip
title={t('common.regenerate')}
mouseEnterDelay={0.8}
open={showRegenerateTooltip}
onOpenChange={setShowRegenerateTooltip}>
<ActionButton className="message-action-button" $softHoverBg={softHoverBg}>
<RefreshCw size={16} />
</ActionButton>
</Tooltip>
</Popconfirm>
)}
{isAssistantMessage && (
<Tooltip title={t('message.mention.title')} mouseEnterDelay={0.8}>
<ActionButton className="message-action-button" onClick={onMentionModel} $softHoverBg={softHoverBg}>
<AtSign size={16} />
</ActionButton>
</Tooltip>
)}
{!isUserMessage && (
<Dropdown
menu={{
style: {
maxHeight: 250,
overflowY: 'auto',
backgroundClip: 'border-box'
},
items: [
...translateLanguageOptions.map((item) => ({
label: item.emoji + ' ' + item.label(),
key: item.langCode,
onClick: () => handleTranslate(item)
})),
...(hasTranslationBlocks
? [
{ type: 'divider' as const },
{
label: '📋 ' + t('common.copy'),
key: 'translate-copy',
onClick: () => {
const translationBlocks = message.blocks
.map((blockId) => blockEntities[blockId])
.filter((block) => block?.type === 'translation')
if (translationBlocks.length > 0) {
const translationContent = translationBlocks
.map((block) => block?.content || '')
.join('\n\n')
.trim()
if (translationBlocks.length > 0) {
const translationContent = translationBlocks
.map((block) => block?.content || '')
.join('\n\n')
.trim()
if (translationContent) {
navigator.clipboard.writeText(translationContent)
window.message.success({ content: t('translate.copied'), key: 'translate-copy' })
} else {
window.message.warning({ content: t('translate.empty'), key: 'translate-copy' })
if (translationContent) {
navigator.clipboard.writeText(translationContent)
window.message.success({ content: t('translate.copied'), key: 'translate-copy' })
} else {
window.message.warning({ content: t('translate.empty'), key: 'translate-copy' })
}
}
}
},
{
label: '✖ ' + t('translate.close'),
key: 'translate-close',
onClick: () => {
const translationBlocks = message.blocks
.map((blockId) => blockEntities[blockId])
.filter((block) => block?.type === 'translation')
.map((block) => block?.id)
if (translationBlocks.length > 0) {
translationBlocks.forEach((blockId) => {
if (blockId) removeMessageBlock(message.id, blockId)
})
window.message.success({ content: t('translate.closed'), key: 'translate-close' })
}
}
}
},
{
label: '✖ ' + t('translate.close'),
key: 'translate-close',
onClick: () => {
const translationBlocks = message.blocks
.map((blockId) => blockEntities[blockId])
.filter((block) => block?.type === 'translation')
.map((block) => block?.id)
if (translationBlocks.length > 0) {
translationBlocks.forEach((blockId) => {
if (blockId) removeMessageBlock(message.id, blockId)
})
window.message.success({ content: t('translate.closed'), key: 'translate-close' })
}
}
}
]
: [])
],
onClick: (e) => e.domEvent.stopPropagation()
}}
trigger={['click']}
placement="top"
arrow>
<Tooltip title={t('chat.translate')} mouseEnterDelay={1.2}>
<ActionButton
className="message-action-button"
onClick={(e) => e.stopPropagation()}
$softHoverBg={softHoverBg}>
<Languages size={16} />
]
: [])
],
onClick: (e) => e.domEvent.stopPropagation()
}}
trigger={['click']}
placement="top"
arrow>
<Tooltip title={t('chat.translate')} mouseEnterDelay={1.2}>
<ActionButton
className="message-action-button"
onClick={(e) => e.stopPropagation()}
$softHoverBg={softHoverBg}>
<Languages size={16} />
</ActionButton>
</Tooltip>
</Dropdown>
)}
{isAssistantMessage && isGrouped && (
<Tooltip title={t('chat.message.useful')} mouseEnterDelay={0.8}>
<ActionButton className="message-action-button" onClick={onUseful} $softHoverBg={softHoverBg}>
{message.useful ? (
<ThumbsUp size={17.5} fill="var(--color-primary)" strokeWidth={0} />
) : (
<ThumbsUp size={16} />
)}
</ActionButton>
</Tooltip>
</Dropdown>
)}
{isAssistantMessage && isGrouped && (
<Tooltip title={t('chat.message.useful')} mouseEnterDelay={0.8}>
<ActionButton className="message-action-button" onClick={onUseful} $softHoverBg={softHoverBg}>
{message.useful ? (
<ThumbsUp size={17.5} fill="var(--color-primary)" strokeWidth={0} />
) : (
<ThumbsUp size={16} />
)}
</ActionButton>
</Tooltip>
)}
<Popconfirm
title={t('message.message.delete.content')}
okButtonProps={{ danger: true }}
icon={<QuestionCircleOutlined style={{ color: 'red' }} />}
onOpenChange={(open) => open && setShowDeleteTooltip(false)}
onConfirm={() => deleteMessage(message.id)}>
<ActionButton className="message-action-button" onClick={(e) => e.stopPropagation()} $softHoverBg={softHoverBg}>
<Tooltip
title={t('common.delete')}
mouseEnterDelay={1}
open={showDeleteTooltip}
onOpenChange={setShowDeleteTooltip}>
<Trash size={16} />
</Tooltip>
</ActionButton>
</Popconfirm>
{!isUserMessage && (
<Dropdown
menu={{ items: dropdownItems, onClick: (e) => e.domEvent.stopPropagation() }}
trigger={['click']}
placement="topRight">
)}
<Popconfirm
title={t('message.message.delete.content')}
okButtonProps={{ danger: true }}
icon={<QuestionCircleOutlined style={{ color: 'red' }} />}
onOpenChange={(open) => open && setShowDeleteTooltip(false)}
onConfirm={() => deleteMessage(message.id)}>
<ActionButton
className="message-action-button"
onClick={(e) => e.stopPropagation()}
$softHoverBg={softHoverBg}>
<Menu size={19} />
<Tooltip
title={t('common.delete')}
mouseEnterDelay={1}
open={showDeleteTooltip}
onOpenChange={setShowDeleteTooltip}>
<Trash size={16} />
</Tooltip>
</ActionButton>
</Dropdown>
)}
</MenusBar>
</Popconfirm>
{!isUserMessage && (
<Dropdown
menu={{ items: dropdownItems, onClick: (e) => e.domEvent.stopPropagation() }}
trigger={['click']}
placement="topRight">
<ActionButton
className="message-action-button"
onClick={(e) => e.stopPropagation()}
$softHoverBg={softHoverBg}>
<Menu size={19} />
</ActionButton>
</Dropdown>
)}
</MenusBar>
</>
)
}
@ -572,7 +582,8 @@ const MenusBar = styled.div`
flex-direction: row;
justify-content: flex-end;
align-items: center;
gap: 6px;
gap: 8px;
margin-top: 5px;
`
const ActionButton = styled.div<{ $softHoverBg?: boolean }>`
@ -582,8 +593,8 @@ const ActionButton = styled.div<{ $softHoverBg?: boolean }>`
flex-direction: row;
justify-content: center;
align-items: center;
width: 30px;
height: 30px;
width: 26px;
height: 26px;
transition: all 0.2s ease;
&:hover {
background-color: ${(props) =>

View File

@ -11,7 +11,7 @@ interface MessageTokensProps {
isLastMessage?: boolean
}
const MessgeTokens: React.FC<MessageTokensProps> = ({ message }) => {
const MessageTokens: React.FC<MessageTokensProps> = ({ message }) => {
const { showTokens } = useSettings()
// const { generating } = useRuntime()
const locateMessage = () => {
@ -106,4 +106,4 @@ const MessageMetadata = styled.div`
}
`
export default MessgeTokens
export default MessageTokens

View File

@ -167,6 +167,7 @@ const Container = styled(Scrollbar)`
display: flex;
flex-direction: column;
padding: 10px;
margin-top: 3px;
`
const TagsContainer = styled.div`

View File

@ -41,7 +41,6 @@ import {
setRenderInputMessageAsMarkdown,
setShowInputEstimatedTokens,
setShowPrompt,
setShowTokens,
setShowTranslateConfirm,
setThoughtAutoCollapse
} from '@renderer/store/settings'
@ -300,11 +299,6 @@ const SettingsTab: FC<Props> = (props) => {
<Switch size="small" checked={showPrompt} onChange={(checked) => dispatch(setShowPrompt(checked))} />
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitleSmall>{t('settings.messages.tokens')}</SettingRowTitleSmall>
<Switch size="small" checked={showTokens} onChange={(checked) => dispatch(setShowTokens(checked))} />
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitleSmall>{t('settings.messages.use_serif_font')}</SettingRowTitleSmall>
<Switch

View File

@ -450,7 +450,7 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
className="topics-tab"
list={sortedTopics}
onUpdate={updateTopics}
style={{ padding: '10px 0 10px 10px' }}
style={{ padding: '13px 0 10px 10px' }}
itemContainerStyle={{ paddingBottom: '8px' }}>
{(topic) => {
const isActive = topic.id === activeTopic?.id