feat: add change message font size feature #22

支持消息字体大小调节
This commit is contained in:
kangfenmao 2024-08-12 20:57:17 +08:00
parent 744a1fedba
commit f7151bd066
14 changed files with 95 additions and 26 deletions

View File

@ -16,6 +16,8 @@ export default defineConfig({
} }
}, },
plugins: [react()], plugins: [react()],
assetsInclude: ['**/*.md'] server: {
hmr: false
}
} }
}) })

View File

@ -107,6 +107,7 @@ body {
display: flex; display: flex;
min-height: 100vh; min-height: 100vh;
color: var(--color-text); color: var(--color-text);
font-size: 14px;
line-height: 1.6; line-height: 1.6;
overflow: hidden; overflow: hidden;
background: transparent !important; background: transparent !important;

View File

@ -1,6 +1,5 @@
.markdown { .markdown {
color: var(--color-text); color: var(--color-text);
font-size: 15px;
line-height: 1.6; line-height: 1.6;
user-select: text; user-select: text;
word-break: break-word; word-break: break-word;

View File

@ -39,7 +39,6 @@ const NavbarLeftContainer = styled.div`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
font-size: 14px;
font-weight: bold; font-weight: bold;
color: var(--color-text-1); color: var(--color-text-1);
` `
@ -49,7 +48,6 @@ const NavbarCenterContainer = styled.div`
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0 ${isMac ? '20px' : '15px'}; padding: 0 ${isMac ? '20px' : '15px'};
font-size: 14px;
font-weight: bold; font-weight: bold;
color: var(--color-text-1); color: var(--color-text-1);
` `

View File

@ -27,7 +27,8 @@ const resources = {
save: 'Save', save: 'Save',
footnotes: 'References', footnotes: 'References',
select: 'Select', select: 'Select',
search: 'Search' search: 'Search',
default: 'Default'
}, },
button: { button: {
add: 'Add', add: 'Add',
@ -183,7 +184,8 @@ const resources = {
'theme.title': 'Theme', 'theme.title': 'Theme',
'theme.dark': 'Dark', 'theme.dark': 'Dark',
'theme.light': 'Light', 'theme.light': 'Light',
'theme.auto': 'Auto' 'theme.auto': 'Auto',
'font_size.title': 'Message Font Size'
}, },
translate: { translate: {
title: 'Translation', title: 'Translation',
@ -241,7 +243,8 @@ const resources = {
you: '用户', you: '用户',
footnote: '引用内容', footnote: '引用内容',
select: '选择', select: '选择',
search: '搜索' search: '搜索',
default: '默认'
}, },
button: { button: {
add: '添加', add: '添加',
@ -336,7 +339,7 @@ const resources = {
settings: { settings: {
title: '设置', title: '设置',
general: '常规设置', general: '常规设置',
provider: '模型提供商', provider: '模型服务',
model: '默认模型', model: '默认模型',
assistant: '默认助手', assistant: '默认助手',
about: '关于我们', about: '关于我们',
@ -398,7 +401,8 @@ const resources = {
'theme.title': '主题', 'theme.title': '主题',
'theme.dark': '深色主题', 'theme.dark': '深色主题',
'theme.light': '浅色主题', 'theme.light': '浅色主题',
'theme.auto': '跟随系统' 'theme.auto': '跟随系统',
'font_size.title': '消息字体大小'
}, },
translate: { translate: {
title: '翻译', title: '翻译',

View File

@ -168,7 +168,6 @@ const AssistantItem = styled.div`
` `
const AssistantName = styled.div` const AssistantName = styled.div`
font-size: 14px;
color: var(--color-text); color: var(--color-text);
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 1; -webkit-line-clamp: 1;

View File

@ -39,7 +39,7 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
const [text, setText] = useState(_text) const [text, setText] = useState(_text)
const [inputFocus, setInputFocus] = useState(false) const [inputFocus, setInputFocus] = useState(false)
const { addTopic } = useAssistant(assistant.id) const { addTopic } = useAssistant(assistant.id)
const { sendMessageShortcut, showInputEstimatedTokens } = useSettings() const { sendMessageShortcut, showInputEstimatedTokens, fontSize } = useSettings()
const [expended, setExpend] = useState(false) const [expended, setExpend] = useState(false)
const [estimateTokenCount, setEstimateTokenCount] = useState(0) const [estimateTokenCount, setEstimateTokenCount] = useState(0)
const generating = useAppSelector((state) => state.runtime.generating) const generating = useAppSelector((state) => state.runtime.generating)
@ -230,6 +230,7 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
styles={{ textarea: { paddingLeft: 0 } }} styles={{ textarea: { paddingLeft: 0 } }}
onFocus={() => setInputFocus(true)} onFocus={() => setInputFocus(true)}
onBlur={() => setInputFocus(false)} onBlur={() => setInputFocus(false)}
style={{ fontSize }}
/> />
</Container> </Container>
) )

View File

@ -38,7 +38,7 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
const avatar = useAvatar() const avatar = useAvatar()
const { t } = useTranslation() const { t } = useTranslation()
const { assistant, model, setModel } = useAssistant(message.assistantId) const { assistant, model, setModel } = useAssistant(message.assistantId)
const { userName, showMessageDivider, messageFont } = useSettings() const { userName, showMessageDivider, messageFont, fontSize } = useSettings()
const { generating } = useRuntime() const { generating } = useRuntime()
const [copied, setCopied] = useState(false) const [copied, setCopied] = useState(false)
@ -135,7 +135,7 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
</UserWrap> </UserWrap>
</AvatarWrapper> </AvatarWrapper>
</MessageHeader> </MessageHeader>
<MessageContent style={{ fontFamily }}> <MessageContent style={{ fontFamily, fontSize }}>
<MessageItem /> <MessageItem />
<MessageFooter style={{ border: messageBorder }}> <MessageFooter style={{ border: messageBorder }}>
{showMenu && ( {showMenu && (

View File

@ -143,7 +143,6 @@ const TopicListItem = styled.div`
padding: 7px 10px; padding: 7px 10px;
cursor: pointer; cursor: pointer;
border-radius: 8px; border-radius: 8px;
font-size: 14px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;

View File

@ -4,10 +4,10 @@ import i18n from '@renderer/i18n'
import LocalStorage from '@renderer/services/storage' import LocalStorage from '@renderer/services/storage'
import { useAppDispatch } from '@renderer/store' import { useAppDispatch } from '@renderer/store'
import { setAvatar } from '@renderer/store/runtime' import { setAvatar } from '@renderer/store/runtime'
import { setLanguage, setUserName, ThemeMode } from '@renderer/store/settings' import { setFontSize, setLanguage, setUserName, ThemeMode } from '@renderer/store/settings'
import { setProxyUrl as _setProxyUrl } from '@renderer/store/settings' import { setProxyUrl as _setProxyUrl } from '@renderer/store/settings'
import { compressImage, isValidProxyUrl } from '@renderer/utils' import { compressImage, isValidProxyUrl } from '@renderer/utils'
import { Avatar, Input, Select, Upload } from 'antd' import { Avatar, Input, Select, Slider, Upload } from 'antd'
import { FC, useState } from 'react' import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -16,7 +16,8 @@ import { SettingContainer, SettingDivider, SettingRow, SettingRowTitle, SettingT
const GeneralSettings: FC = () => { const GeneralSettings: FC = () => {
const avatar = useAvatar() const avatar = useAvatar()
const { language, proxyUrl: storeProxyUrl, userName, theme, setTheme } = useSettings() const { language, proxyUrl: storeProxyUrl, userName, theme, setTheme, fontSize } = useSettings()
const [fontSizeValue, setFontSizeValue] = useState(fontSize)
const [proxyUrl, setProxyUrl] = useState<string | undefined>(storeProxyUrl) const [proxyUrl, setProxyUrl] = useState<string | undefined>(storeProxyUrl)
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const { t } = useTranslation() const { t } = useTranslation()
@ -100,6 +101,27 @@ const GeneralSettings: FC = () => {
/> />
</SettingRow> </SettingRow>
<SettingDivider /> <SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.font_size.title')}</SettingRowTitle>
<Slider
style={{ width: 290 }}
value={fontSizeValue}
onChange={(value) => setFontSizeValue(value)}
onChangeComplete={(value) => {
dispatch(setFontSize(value))
console.debug('set font size', value)
}}
min={12}
max={18}
step={1}
marks={{
12: <span style={{ fontSize: '12px' }}>A</span>,
14: <span style={{ fontSize: '14px' }}>{t('common.default')}</span>,
18: <span style={{ fontSize: '18px' }}>A</span>
}}
/>
</SettingRow>
<SettingDivider />
<SettingRow> <SettingRow>
<SettingRowTitle>{t('settings.proxy.title')}</SettingRowTitle> <SettingRowTitle>{t('settings.proxy.title')}</SettingRowTitle>
<Input <Input

View File

@ -1,3 +1,10 @@
import {
CloudOutlined,
CodeSandboxOutlined,
InfoCircleOutlined,
MessageOutlined,
SettingOutlined
} from '@ant-design/icons'
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
import { FC } from 'react' import { FC } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@ -24,19 +31,34 @@ const SettingsPage: FC = () => {
<ContentContainer> <ContentContainer>
<SettingMenus> <SettingMenus>
<MenuItemLink to="/settings/provider"> <MenuItemLink to="/settings/provider">
<MenuItem className={isRoute('/settings/provider')}>{t('settings.provider')}</MenuItem> <MenuItem className={isRoute('/settings/provider')}>
<CloudOutlined />
{t('settings.provider')}
</MenuItem>
</MenuItemLink> </MenuItemLink>
<MenuItemLink to="/settings/model"> <MenuItemLink to="/settings/model">
<MenuItem className={isRoute('/settings/model')}>{t('settings.model')}</MenuItem> <MenuItem className={isRoute('/settings/model')}>
<CodeSandboxOutlined />
{t('settings.model')}
</MenuItem>
</MenuItemLink> </MenuItemLink>
<MenuItemLink to="/settings/assistant"> <MenuItemLink to="/settings/assistant">
<MenuItem className={isRoute('/settings/assistant')}>{t('settings.assistant')}</MenuItem> <MenuItem className={isRoute('/settings/assistant')}>
<MessageOutlined />
{t('settings.assistant')}
</MenuItem>
</MenuItemLink> </MenuItemLink>
<MenuItemLink to="/settings/general"> <MenuItemLink to="/settings/general">
<MenuItem className={isRoute('/settings/general')}>{t('settings.general')}</MenuItem> <MenuItem className={isRoute('/settings/general')}>
<SettingOutlined />
{t('settings.general')}
</MenuItem>
</MenuItemLink> </MenuItemLink>
<MenuItemLink to="/settings/about"> <MenuItemLink to="/settings/about">
<MenuItem className={isRoute('/settings/about')}>{t('settings.about')}</MenuItem> <MenuItem className={isRoute('/settings/about')}>
<InfoCircleOutlined />
{t('settings.about')}
</MenuItem>
</MenuItemLink> </MenuItemLink>
</SettingMenus> </SettingMenus>
<SettingContent> <SettingContent>
@ -81,13 +103,20 @@ const MenuItemLink = styled(Link)`
` `
const MenuItem = styled.li` const MenuItem = styled.li`
display: flex;
flex-direction: row;
align-items: center;
gap: 8px;
padding: 6px 10px; padding: 6px 10px;
width: 100%; width: 100%;
cursor: pointer; cursor: pointer;
border-radius: 5px; border-radius: 5px;
font-size: 14px;
font-weight: 500; font-weight: 500;
transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out;
.anticon {
font-size: 16px;
opacity: 0.8;
}
&:hover { &:hover {
background: var(--color-primary-soft); background: var(--color-primary-soft);
} }

View File

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

View File

@ -287,6 +287,15 @@ const migrateConfig = {
} }
} }
} }
},
'20': (state: RootState) => {
return {
...state,
settings: {
...state.settings,
fontSize: 14
}
}
} }
} }

View File

@ -19,6 +19,7 @@ export interface SettingsState {
messageFont: 'system' | 'serif' messageFont: 'system' | 'serif'
showInputEstimatedTokens: boolean showInputEstimatedTokens: boolean
theme: ThemeMode theme: ThemeMode
fontSize: number
} }
const initialState: SettingsState = { const initialState: SettingsState = {
@ -31,7 +32,8 @@ const initialState: SettingsState = {
showMessageDivider: false, showMessageDivider: false,
messageFont: 'system', messageFont: 'system',
showInputEstimatedTokens: false, showInputEstimatedTokens: false,
theme: ThemeMode.light theme: ThemeMode.light,
fontSize: 14
} }
const settingsSlice = createSlice({ const settingsSlice = createSlice({
@ -70,6 +72,9 @@ const settingsSlice = createSlice({
}, },
setTheme: (state, action: PayloadAction<ThemeMode>) => { setTheme: (state, action: PayloadAction<ThemeMode>) => {
state.theme = action.payload state.theme = action.payload
},
setFontSize: (state, action: PayloadAction<number>) => {
state.fontSize = action.payload
} }
} }
}) })
@ -85,7 +90,8 @@ export const {
setShowMessageDivider, setShowMessageDivider,
setMessageFont, setMessageFont,
setShowInputEstimatedTokens, setShowInputEstimatedTokens,
setTheme setTheme,
setFontSize
} = settingsSlice.actions } = settingsSlice.actions
export default settingsSlice.reducer export default settingsSlice.reducer