From 41c3895da484f2038f6e34500ce87c2b9f0eb158 Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Fri, 1 Nov 2024 21:50:40 +0800 Subject: [PATCH] feat: add message card style switch --- src/renderer/src/hooks/useSettings.ts | 9 ++++ src/renderer/src/i18n/locales/en-us.json | 5 ++- src/renderer/src/i18n/locales/zh-cn.json | 5 ++- src/renderer/src/i18n/locales/zh-tw.json | 5 ++- src/renderer/src/pages/home/Chat.tsx | 34 +++++++++++++-- .../src/pages/home/Inputbar/Inputbar.tsx | 20 +++++---- .../src/pages/home/Messages/Message.tsx | 42 +++++++++---------- .../src/pages/home/Messages/MessageHeader.tsx | 23 +++++----- .../src/pages/home/Messages/Prompt.tsx | 4 +- src/renderer/src/pages/home/Tabs/Settings.tsx | 14 +++++++ src/renderer/src/store/index.ts | 2 +- src/renderer/src/store/migrate.ts | 4 ++ src/renderer/src/store/settings.ts | 8 +++- 13 files changed, 123 insertions(+), 52 deletions(-) diff --git a/src/renderer/src/hooks/useSettings.ts b/src/renderer/src/hooks/useSettings.ts index 3d253b8d..47e93766 100644 --- a/src/renderer/src/hooks/useSettings.ts +++ b/src/renderer/src/hooks/useSettings.ts @@ -28,3 +28,12 @@ export function useSettings() { } } } + +export function useMessageStyle() { + const { messageStyle } = useSettings() + const isBubbleStyle = messageStyle === 'bubble' + + return { + isBubbleStyle + } +} diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 195c9a99..ad039f76 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -64,7 +64,10 @@ "upgrade.success.content": "Please restart the application to complete the upgrade", "upgrade.success.button": "Restart", "topic.added": "New topic added", - "save.success.title": "Saved successfully" + "save.success.title": "Saved successfully", + "message.style": "Message Style", + "message.style.bubble": "Bubble", + "message.style.plain": "Plain" }, "chat": { "save": "Save", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 17fc7d11..16af530a 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -64,7 +64,10 @@ "upgrade.success.content": "重启用以完成升级", "upgrade.success.button": "重启", "topic.added": "话题添加成功", - "save.success.title": "保存成功" + "save.success.title": "保存成功", + "message.style": "消息样式", + "message.style.bubble": "气泡", + "message.style.plain": "简洁" }, "chat": { "save": "保存", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 8eef5e71..b06f417a 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -64,7 +64,10 @@ "upgrade.success.content": "請重新啟動應用以完成升級", "upgrade.success.button": "重新啟動", "topic.added": "新話題已添加", - "save.success.title": "保存成功" + "save.success.title": "保存成功", + "message.style": "消息樣式", + "message.style.bubble": "氣泡", + "message.style.plain": "簡潔" }, "chat": { "save": "保存", diff --git a/src/renderer/src/pages/home/Chat.tsx b/src/renderer/src/pages/home/Chat.tsx index caadb5d0..e5e98df4 100644 --- a/src/renderer/src/pages/home/Chat.tsx +++ b/src/renderer/src/pages/home/Chat.tsx @@ -19,11 +19,11 @@ interface Props { const Chat: FC = (props) => { const { assistant } = useAssistant(props.assistant.id) - const { topicPosition } = useSettings() + const { topicPosition, messageStyle } = useSettings() const { showTopics } = useShowTopics() return ( - +
= ({ assistant, setActiveTopic }) => { const containerRef = useRef(null) const { showTopics, toggleShowTopics } = useShowTopics() const { searching } = useRuntime() + const { isBubbleStyle } = useMessageStyle() const dispatch = useAppDispatch() const isVision = useMemo(() => isVisionModel(model), [model]) @@ -299,7 +300,7 @@ const Inputbar: FC = ({ assistant, setActiveTopic }) => { autoFocus contextMenu="true" variant="borderless" - rows={2} + rows={isBubbleStyle ? 2 : 1} ref={textareaRef} style={{ fontSize }} styles={{ textarea: TextareaStyle }} @@ -375,18 +376,19 @@ const Container = styled.div` flex-direction: column; ` +const InputBarContainer = styled.div` + border: 1px solid var(--color-border-soft); + transition: all 0.3s ease; + position: relative; + margin: 0 20px 15px 20px; + border-radius: 10px; +` + const TextareaStyle: CSSProperties = { paddingLeft: 0, padding: '10px 15px 8px' } -const InputBarContainer = styled.div` - border-top: 1px solid var(--color-border-mute); - transition: all 0.3s ease; - position: relative; - background: var(--color-background); -` - const Textarea = styled(TextArea)` padding: 0; border-radius: 0; diff --git a/src/renderer/src/pages/home/Messages/Message.tsx b/src/renderer/src/pages/home/Messages/Message.tsx index 95a3a0df..145e0455 100644 --- a/src/renderer/src/pages/home/Messages/Message.tsx +++ b/src/renderer/src/pages/home/Messages/Message.tsx @@ -2,7 +2,7 @@ import { FONT_FAMILY } from '@renderer/config/constant' import db from '@renderer/databases' import { useAssistant } from '@renderer/hooks/useAssistant' import { useModel } from '@renderer/hooks/useModel' -import { useSettings } from '@renderer/hooks/useSettings' +import { useMessageStyle, useSettings } from '@renderer/hooks/useSettings' import { fetchChatCompletion } from '@renderer/services/ApiService' import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService' import { estimateMessageUsage } from '@renderer/services/TokenService' @@ -42,11 +42,13 @@ const MessageItem: FC = ({ const { t } = useTranslation() const { assistant, setModel } = useAssistant(message.assistantId) const model = useModel(message.modelId) + const { isBubbleStyle } = useMessageStyle() const { showMessageDivider, messageFont, fontSize } = useSettings() const messageContainerRef = useRef(null) const isLastMessage = index === 0 const isAssistantMessage = message.role === 'assistant' + const showMenubar = !message.status.includes('ing') const fontFamily = useMemo(() => { @@ -54,6 +56,11 @@ const MessageItem: FC = ({ }, [messageFont]) const messageBorder = showMessageDivider ? undefined : 'none' + const messageBackground = isBubbleStyle + ? isAssistantMessage + ? 'var(--chat-background-assistant)' + : 'var(--chat-background-user)' + : undefined const onEditMessage = useCallback( (msg: Message) => { @@ -139,17 +146,19 @@ const MessageItem: FC = ({ 'message-user': !isAssistantMessage })} ref={messageContainerRef} - style={{ alignItems: isAssistantMessage ? 'start' : 'end' }}> + style={isBubbleStyle ? { alignItems: isAssistantMessage ? 'start' : 'end' } : undefined}> + className="message-content-container" + style={{ fontFamily, fontSize, background: messageBackground }}> {showMenubar && ( - + + = ({ onEditMessage={onEditMessage} onDeleteMessage={onDeleteMessage} /> - )} @@ -177,17 +185,6 @@ const MessageContainer = styled.div` &.message-highlight { background-color: var(--color-primary-mute); } - &.message-user { - .markdown, - .anticon, - .iconfont, - .message-tokens { - color: var(--chat-text-user); - } - .message-action-button:hover { - background-color: var(--color-white-soft); - } - } .menubar { opacity: 0; transition: opacity 0.2s ease; @@ -208,9 +205,8 @@ const MessageContentContainer = styled.div` flex: 1; flex-direction: column; justify-content: space-between; - margin: 5px 0; - border-radius: 8px; - padding: 10px 15px 0 15px; + margin-left: 46px; + margin-top: 5px; ` const MessageFooter = styled.div` diff --git a/src/renderer/src/pages/home/Messages/MessageHeader.tsx b/src/renderer/src/pages/home/Messages/MessageHeader.tsx index 7954c211..209b42b8 100644 --- a/src/renderer/src/pages/home/Messages/MessageHeader.tsx +++ b/src/renderer/src/pages/home/Messages/MessageHeader.tsx @@ -4,12 +4,12 @@ import { startMinAppById } from '@renderer/config/minapps' import { getModelLogo } from '@renderer/config/models' import { useTheme } from '@renderer/context/ThemeProvider' import useAvatar from '@renderer/hooks/useAvatar' -import { useSettings } from '@renderer/hooks/useSettings' +import { useMessageStyle, useSettings } from '@renderer/hooks/useSettings' import { Assistant, Message, Model } from '@renderer/types' import { firstLetter, removeLeadingEmoji } from '@renderer/utils' import { Avatar } from 'antd' import dayjs from 'dayjs' -import { FC, useCallback, useMemo } from 'react' +import { CSSProperties, FC, useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' @@ -24,8 +24,7 @@ const MessageHeader: FC = ({ assistant, model, message }) => { const { theme } = useTheme() const { userName } = useSettings() const { t } = useTranslation() - - const isAssistantMessage = message.role === 'assistant' + const { isBubbleStyle } = useMessageStyle() const avatarSource = useMemo(() => { if (isLocalAi) return AppLogo @@ -39,19 +38,23 @@ const MessageHeader: FC = ({ assistant, model, message }) => { return userName || t('common.you') }, [message.role, model?.id, model?.name, t, userName]) - const avatarName = useMemo(() => firstLetter(assistant?.name).toUpperCase(), [assistant?.name]) + const isAssistantMessage = message.role === 'assistant' + const avatarName = useMemo(() => firstLetter(assistant?.name).toUpperCase(), [assistant?.name]) const username = useMemo(() => removeLeadingEmoji(getUserName()), [getUserName]) const showMiniApp = () => model?.provider && startMinAppById(model?.provider) + const avatarStyle: CSSProperties | undefined = isBubbleStyle + ? { + flexDirection: isAssistantMessage ? 'row' : 'row-reverse', + textAlign: isAssistantMessage ? 'left' : 'right' + } + : undefined + return ( - + {isAssistantMessage ? ( = ({ assistant }) => { } return ( - AssistantSettingsPopup.show({ assistant })}> + AssistantSettingsPopup.show({ assistant })}> {prompt} ) @@ -26,7 +26,7 @@ const Prompt: FC = ({ assistant }) => { const Container = styled.div` padding: 10px 20px; - background-color: var(--chat-background-assistant); + background-color: var(--color-background-soft); margin-bottom: 20px; margin: 0 20px 0 20px; border-radius: 6px; diff --git a/src/renderer/src/pages/home/Tabs/Settings.tsx b/src/renderer/src/pages/home/Tabs/Settings.tsx index 6c9de3a1..7ccb1ba4 100644 --- a/src/renderer/src/pages/home/Tabs/Settings.tsx +++ b/src/renderer/src/pages/home/Tabs/Settings.tsx @@ -11,6 +11,7 @@ import { setFontSize, setMathEngine, setMessageFont, + setMessageStyle, setPasteLongTextAsFile, setRenderInputMessageAsMarkdown, setShowInputEstimatedTokens, @@ -35,6 +36,7 @@ const SettingsTab: FC = (props) => { const [maxTokens, setMaxTokens] = useState(assistant?.settings?.maxTokens ?? 0) const [streamOutput, setStreamOutput] = useState(assistant?.settings?.streamOutput ?? true) const [fontSizeValue, setFontSizeValue] = useState(fontSize) + const { messageStyle } = useSettings() const { t } = useTranslation() const dispatch = useAppDispatch() @@ -214,6 +216,18 @@ const SettingsTab: FC = (props) => { /> + + {t('message.message.style')} + + + {t('settings.messages.math_engine')}