feat(settings): add messageFont setting

This commit is contained in:
kangfenmao 2024-07-24 12:25:36 +08:00
parent 3625eefec4
commit 51f4653cde
10 changed files with 63 additions and 45 deletions

View File

@ -1,6 +1,5 @@
.markdown {
color: #f1f1f1;
font-family: Georgia, Cambria, 'Times New Roman', Times, serif;
font-size: 16px;
line-height: 1.6;
user-select: text;

View File

@ -32,7 +32,7 @@ const Sidebar: FC = () => {
</Menus>
</MainMenus>
<Menus>
<StyledLink to="/settings/provider">
<StyledLink to="/settings/general">
<Icon className={pathname.startsWith('/settings') ? 'active' : ''}>
<i className="iconfont icon-setting"></i>
</Icon>

View File

@ -105,7 +105,9 @@ const resources = {
assistant: 'Default Assistant',
about: 'About & Feedback',
'general.title': 'General Settings',
'general.message.title': 'Message Settings',
'general.message.divider': 'Show divider between messages',
'general.message.use_serif_font': 'Use serif font',
'general.user_name': 'User Name',
'general.user_name.placeholder': 'Enter your name',
'provider.api_key': 'API Key',
@ -257,7 +259,9 @@ const resources = {
'general.title': '常规设置',
'general.user_name': '用户名',
'general.user_name.placeholder': '请输入用户名',
'general.message.title': '消息设置',
'general.message.divider': '消息分割线',
'general.message.use_serif_font': '使用衬线字体',
'provider.api_key': 'API 密钥',
'provider.check': '检查',
'provider.get_api_key': '点击这里获取密钥',

View File

@ -1,21 +1,20 @@
import { Message } from '@renderer/types'
import { Avatar, Tooltip } from 'antd'
import { FC } from 'react'
import styled from 'styled-components'
import useAvatar from '@renderer/hooks/useAvatar'
import { CopyOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons'
import Markdown from 'react-markdown'
import CodeBlock from './CodeBlock'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
import { getModelLogo } from '@renderer/config/provider'
import { CopyOutlined, DeleteOutlined, EditOutlined, SyncOutlined } from '@ant-design/icons'
import Logo from '@renderer/assets/images/logo.png'
import { SyncOutlined } from '@ant-design/icons'
import { firstLetter } from '@renderer/utils'
import { useTranslation } from 'react-i18next'
import { isEmpty, upperFirst } from 'lodash'
import dayjs from 'dayjs'
import { getModelLogo } from '@renderer/config/provider'
import { useAssistant } from '@renderer/hooks/useAssistant'
import useAvatar from '@renderer/hooks/useAvatar'
import { useSettings } from '@renderer/hooks/useSettings'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
import { Message } from '@renderer/types'
import { firstLetter } from '@renderer/utils'
import { Avatar, Tooltip } from 'antd'
import dayjs from 'dayjs'
import { isEmpty, upperFirst } from 'lodash'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import Markdown from 'react-markdown'
import styled from 'styled-components'
import CodeBlock from './CodeBlock'
interface Props {
message: Message
@ -29,7 +28,7 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
const avatar = useAvatar()
const { t } = useTranslation()
const { assistant } = useAssistant(message.assistantId)
const { userName, showMessageDivider } = useSettings()
const { userName, showMessageDivider, messageFont } = useSettings()
const isLastMessage = index === 0
const isUserMessage = message.role === 'user'
@ -79,8 +78,11 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
return userName || t('common.you')
}
const fontFamily = messageFont === 'serif' ? "Georgia, Cambria, 'Times New Roman', Times, serif" : undefined
const messageBorder = showMessageDivider ? undefined : 'none'
return (
<MessageContainer key={message.id} className="message" style={{ border: showMessageDivider ? undefined : 'none' }}>
<MessageContainer key={message.id} className="message" style={{ border: messageBorder }}>
<MessageHeader>
<AvatarWrapper>
{message.role === 'assistant' ? (
@ -101,7 +103,7 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
</MessageMetadata>
)}
</MessageHeader>
<MessageContent>
<MessageContent style={{ fontFamily }}>
{message.status === 'sending' && (
<MessageContentLoading>
<SyncOutlined spin size={24} />

View File

@ -31,7 +31,7 @@ const NavigationCenter: FC<Props> = ({ activeAssistant }) => {
type: 'group',
children: p.models.map((m) => ({
key: m.id,
label: m.name,
label: upperFirst(m.name),
style: m.id === model?.id ? { color: colorPrimary } : undefined,
onClick: () => setModel(m)
}))

View File

@ -8,14 +8,14 @@ import useAvatar from '@renderer/hooks/useAvatar'
import { useAppDispatch } from '@renderer/store'
import { setAvatar } from '@renderer/store/runtime'
import { useSettings } from '@renderer/hooks/useSettings'
import { setLanguage, setShowMessageDivider, setUserName } from '@renderer/store/settings'
import { setLanguage, setMessageFont, setShowMessageDivider, setUserName } from '@renderer/store/settings'
import { useTranslation } from 'react-i18next'
import { setProxyUrl as _setProxyUrl } from '@renderer/store/settings'
import i18n from '@renderer/i18n'
const GeneralSettings: FC = () => {
const avatar = useAvatar()
const { language, proxyUrl: storeProxyUrl, userName, showMessageDivider } = useSettings()
const { language, proxyUrl: storeProxyUrl, userName, showMessageDivider, messageFont } = useSettings()
const [proxyUrl, setProxyUrl] = useState<string | undefined>(storeProxyUrl)
const dispatch = useAppDispatch()
const { t } = useTranslation()
@ -97,11 +97,21 @@ const GeneralSettings: FC = () => {
/>
</SettingRow>
<SettingDivider />
<SettingTitle style={{ marginTop: 20 }}>{t('settings.general.message.title')}</SettingTitle>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.general.message.divider')}</SettingRowTitle>
<Switch checked={showMessageDivider} onChange={(checked) => dispatch(setShowMessageDivider(checked))} />
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.general.message.use_serif_font')}</SettingRowTitle>
<Switch
checked={messageFont === 'serif'}
onChange={(checked) => dispatch(setMessageFont(checked ? 'serif' : 'system'))}
/>
</SettingRow>
<SettingDivider />
</SettingContainer>
)
}

View File

@ -22,6 +22,9 @@ const SettingsPage: FC = () => {
</Navbar>
<ContentContainer>
<SettingMenus>
<MenuItemLink to="/settings/general">
<MenuItem className={isRoute('/settings/general')}>{t('settings.general')}</MenuItem>
</MenuItemLink>
<MenuItemLink to="/settings/provider">
<MenuItem className={isRoute('/settings/provider')}>{t('settings.provider')}</MenuItem>
</MenuItemLink>
@ -31,9 +34,6 @@ const SettingsPage: FC = () => {
<MenuItemLink to="/settings/assistant">
<MenuItem className={isRoute('/settings/assistant')}>{t('settings.assistant')}</MenuItem>
</MenuItemLink>
<MenuItemLink to="/settings/general">
<MenuItem className={isRoute('/settings/general')}>{t('settings.general')}</MenuItem>
</MenuItemLink>
<MenuItemLink to="/settings/about">
<MenuItem className={isRoute('/settings/about')}>{t('settings.about')}</MenuItem>
</MenuItemLink>

View File

@ -19,7 +19,7 @@ const persistedReducer = persistReducer(
{
key: 'cherry-studio',
storage,
version: 15,
version: 16,
blacklist: ['runtime'],
migrate
},

View File

@ -5,8 +5,7 @@ import { isEmpty } from 'lodash'
import i18n from '@renderer/i18n'
import { Assistant } from '@renderer/types'
const migrate = createMigrate({
// @ts-ignore store type is unknown
const migrateConfig = {
'2': (state: RootState) => {
return {
...state,
@ -26,7 +25,6 @@ const migrate = createMigrate({
}
}
},
// @ts-ignore store type is unknown
'3': (state: RootState) => {
return {
...state,
@ -46,7 +44,6 @@ const migrate = createMigrate({
}
}
},
// @ts-ignore store type is unknown
'4': (state: RootState) => {
return {
...state,
@ -66,7 +63,6 @@ const migrate = createMigrate({
}
}
},
// @ts-ignore store type is unknown
'5': (state: RootState) => {
return {
...state,
@ -86,7 +82,6 @@ const migrate = createMigrate({
}
}
},
// @ts-ignore store type is unknown
'6': (state: RootState) => {
return {
...state,
@ -106,7 +101,6 @@ const migrate = createMigrate({
}
}
},
// @ts-ignore store type is unknown
'7': (state: RootState) => {
return {
...state,
@ -116,7 +110,6 @@ const migrate = createMigrate({
}
}
},
// @ts-ignore store type is unknown
'8': (state: RootState) => {
const fixAssistantName = (assistant: Assistant) => {
if (isEmpty(assistant.name)) {
@ -142,7 +135,6 @@ const migrate = createMigrate({
}
}
},
// @ts-ignore store type is unknown
'9': (state: RootState) => {
return {
...state,
@ -157,7 +149,6 @@ const migrate = createMigrate({
}
}
},
// @ts-ignore store type is unknown
'10': (state: RootState) => {
return {
...state,
@ -178,7 +169,6 @@ const migrate = createMigrate({
}
}
},
// @ts-ignore store type is unknown
'11': (state: RootState) => {
return {
...state,
@ -208,7 +198,6 @@ const migrate = createMigrate({
}
}
},
// @ts-ignore store type is unknown
'12': (state: RootState) => {
return {
...state,
@ -229,7 +218,6 @@ const migrate = createMigrate({
}
}
},
// @ts-ignore store type is unknown
'13': (state: RootState) => {
return {
...state,
@ -244,7 +232,6 @@ const migrate = createMigrate({
}
}
},
// @ts-ignore store type is unknown
'14': (state: RootState) => {
return {
...state,
@ -255,7 +242,6 @@ const migrate = createMigrate({
}
}
},
// @ts-ignore store type is unknown
'15': (state: RootState) => {
return {
...state,
@ -265,7 +251,18 @@ const migrate = createMigrate({
showMessageDivider: true
}
}
},
'16': (state: RootState) => {
return {
...state,
settings: {
...state.settings,
messageFont: 'system'
}
}
}
})
}
const migrate = createMigrate(migrateConfig as any)
export default migrate

View File

@ -10,6 +10,7 @@ export interface SettingsState {
proxyUrl?: string
userName: string
showMessageDivider: boolean
messageFont: 'system' | 'serif'
}
const initialState: SettingsState = {
@ -19,7 +20,8 @@ const initialState: SettingsState = {
language: navigator.language,
proxyUrl: undefined,
userName: '',
showMessageDivider: true
showMessageDivider: true,
messageFont: 'system'
}
const settingsSlice = createSlice({
@ -46,6 +48,9 @@ const settingsSlice = createSlice({
},
setShowMessageDivider: (state, action: PayloadAction<boolean>) => {
state.showMessageDivider = action.payload
},
setMessageFont: (state, action: PayloadAction<'system' | 'serif'>) => {
state.messageFont = action.payload
}
}
})
@ -57,7 +62,8 @@ export const {
setLanguage,
setProxyUrl,
setUserName,
setShowMessageDivider
setShowMessageDivider,
setMessageFont
} = settingsSlice.actions
export default settingsSlice.reducer