feat: add setting panel

This commit is contained in:
kangfenmao 2024-07-24 16:03:02 +08:00
parent 9d96b826e2
commit d0280186bc
15 changed files with 256 additions and 233 deletions

View File

@ -27,6 +27,10 @@
--color-background-soft: var(--color-black-soft);
--color-background-mute: var(--color-black-mute);
--color-primary: #00b96b;
--color-primary-soft: #00b96b99;
--color-primary-mute: #00b96b33;
--color-text: var(--color-text-1);
--color-icon: #ffffff99;
--color-icon-white: #ffffff;
@ -36,8 +40,8 @@
--navbar-background: #1f1f1f;
--navbar-height: 42px;
--sidebar-width: 55px;
--assistants-width: 250px;
--topic-list-width: 250px;
--assistants-width: 245px;
--topic-list-width: 260px;
--settings-width: var(--assistants-width);
--status-bar-height: 40px;
--input-bar-height: 125px;
@ -103,29 +107,3 @@ body,
#inputbar .ant-input {
resize: none;
}
/* 全局初始化滚动条样式 */
::-webkit-scrollbar {
width: 5px;
height: 5px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.2);
}
::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.4);
}
/* Safari 和 Chrome */
@media screen and (-webkit-min-device-pixel-ratio: 0) {
body {
scrollbar-width: thin; /* 告诉 FF 用细滚动条 */
scrollbar-color: rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.1); /* FF 前面色后面色 */
}
}

View File

@ -0,0 +1,15 @@
/* 全局初始化滚动条样式 */
::-webkit-scrollbar {
width: 3px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.2);
&:hover {
background: rgba(255, 255, 255, 0.4);
}
}

View File

@ -5,6 +5,7 @@ import { setAvatar } from '@renderer/store/runtime'
import { runAsyncFunction } from '@renderer/utils'
import { useEffect } from 'react'
import { useSettings } from './useSettings'
import { isWindows } from '@renderer/config/constant'
export function useAppInit() {
const dispatch = useAppDispatch()
@ -28,4 +29,8 @@ export function useAppInit() {
useEffect(() => {
proxyUrl && window.api.setProxy(proxyUrl)
}, [proxyUrl])
useEffect(() => {
isWindows && import('@renderer/assets/styles/scrollbar.scss')
}, [])
}

View File

@ -1,13 +1,15 @@
import { useAppDispatch, useAppSelector } from '@renderer/store'
import { toggleRightSidebar, toggleShowAssistants } from '@renderer/store/settings'
import { setShowRightSidebar, toggleRightSidebar, toggleShowAssistants } from '@renderer/store/settings'
export function useShowRightSidebar() {
const showRightSidebar = useAppSelector((state) => state.settings.showRightSidebar)
const dispatch = useAppDispatch()
return {
showRightSidebar,
toggleRightSidebar: () => dispatch(toggleRightSidebar())
rightSidebarShown: showRightSidebar,
toggleRightSidebar: () => dispatch(toggleRightSidebar()),
showRightSidebar: () => dispatch(setShowRightSidebar(true)),
hideRightSidebar: () => dispatch(setShowRightSidebar(false))
}
}

View File

@ -51,8 +51,6 @@ const resources = {
'default.description': "Hello, I'm Default Assistant. You can start chatting with me right away",
'default.topic.name': 'Default Topic',
'topics.title': 'Topics',
'topics.hide_topics': 'Hide Topics',
'topics.show_topics': 'Show Topics',
'topics.auto_rename': 'Auto Rename',
'topics.edit.title': 'Rename',
'topics.edit.placeholder': 'Enter new name',
@ -103,14 +101,15 @@ const resources = {
model: 'Model Settings',
assistant: 'Default Assistant',
about: 'About & Feedback',
'messages.model.title': 'Model Settings',
'messages.title': 'Message Settings',
'messages.divider': 'Show divider between messages',
'messages.use_serif_font': 'Use serif font',
'messages.input.title': 'Input Settings',
'messages.input.show_estimated_tokens': 'Show estimated input tokens',
'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',
'general.input.title': 'Input Settings',
'general.input.show_estimated_tokens': 'Show estimated input tokens',
'provider.api_key': 'API Key',
'provider.check': 'Check',
'provider.get_api_key': 'Get API Key',
@ -203,8 +202,6 @@ const resources = {
'default.description': '你好,我是默认助手。你可以立刻开始跟我聊天。',
'default.topic.name': '默认话题',
'topics.title': '话题',
'topics.hide_topics': '隐藏话题',
'topics.show_topics': '显示话题',
'topics.auto_rename': 'AI 重命名',
'topics.edit.title': '重命名',
'topics.edit.placeholder': '输入新名称',
@ -256,14 +253,15 @@ const resources = {
model: '模型设置',
assistant: '默认助手',
about: '关于我们',
'messages.model.title': '模型设置',
'messages.title': '消息设置',
'messages.divider': '消息分割线',
'messages.use_serif_font': '使用衬线字体',
'messages.input.title': '输入设置',
'messages.input.show_estimated_tokens': '状态显示',
'general.title': '常规设置',
'general.user_name': '用户名',
'general.user_name.placeholder': '请输入用户名',
'general.message.title': '消息设置',
'general.message.divider': '消息分割线',
'general.message.use_serif_font': '使用衬线字体',
'general.input.title': '输入设置',
'general.input.show_estimated_tokens': '状态显示',
'provider.api_key': 'API 密钥',
'provider.check': '检查',
'provider.get_api_key': '点击这里获取密钥',

View File

@ -6,18 +6,15 @@ import Chat from './components/Chat'
import Assistants from './components/Assistants'
import { uuid } from '@renderer/utils'
import { useShowAssistants, useShowRightSidebar } from '@renderer/hooks/useStore'
import { Tooltip } from 'antd'
import Navigation from './components/NavigationCenter'
import { useTranslation } from 'react-i18next'
import { isMac, isWindows } from '@renderer/config/constant'
const HomePage: FC = () => {
const { assistants, addAssistant } = useAssistants()
const [activeAssistant, setActiveAssistant] = useState(assistants[0])
const { showRightSidebar, toggleRightSidebar } = useShowRightSidebar()
const { rightSidebarShown, toggleRightSidebar } = useShowRightSidebar()
const { showAssistants, toggleShowAssistants } = useShowAssistants()
const { defaultAssistant } = useDefaultAssistant()
const { t } = useTranslation()
const onCreateAssistant = () => {
const assistant = { ...defaultAssistant, id: uuid() }
@ -40,14 +37,9 @@ const HomePage: FC = () => {
)}
<Navigation activeAssistant={activeAssistant} />
<NavbarRight style={{ justifyContent: 'flex-end', paddingRight: isWindows ? 140 : 8 }}>
<Tooltip
placement="left"
title={showRightSidebar ? t('assistant.topics.hide_topics') : t('assistant.topics.show_topics')}
arrow>
<NewButton onClick={toggleRightSidebar}>
<i className={`iconfont ${showRightSidebar ? 'icon-showsidebarhoriz' : 'icon-hidesidebarhoriz'}`} />
</NewButton>
</Tooltip>
<NewButton onClick={toggleRightSidebar}>
<i className={`iconfont ${rightSidebarShown ? 'icon-showsidebarhoriz' : 'icon-hidesidebarhoriz'}`} />
</NewButton>
</NavbarRight>
</Navbar>
<ContentContainer>

View File

@ -4,7 +4,7 @@ import styled from 'styled-components'
import Inputbar from './Inputbar'
import Messages from './Messages'
import { Flex } from 'antd'
import Topics from './Topics'
import RightSidebar from './RightSidebar'
import { useAssistant } from '@renderer/hooks/useAssistant'
import { useActiveTopic } from '@renderer/hooks/useTopic'
@ -22,7 +22,7 @@ const Chat: FC<Props> = (props) => {
<Messages assistant={assistant} topic={activeTopic} />
<Inputbar assistant={assistant} setActiveTopic={setActiveTopic} />
</Flex>
<Topics assistant={assistant} activeTopic={activeTopic} setActiveTopic={setActiveTopic} />
<RightSidebar assistant={assistant} activeTopic={activeTopic} setActiveTopic={setActiveTopic} />
</Container>
)
}

View File

@ -10,7 +10,6 @@ import {
} from '@ant-design/icons'
import { useAssistant } from '@renderer/hooks/useAssistant'
import { useSettings } from '@renderer/hooks/useSettings'
import { useShowRightSidebar } from '@renderer/hooks/useStore'
import { getDefaultTopic } from '@renderer/services/assistant'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
import store, { useAppSelector } from '@renderer/store'
@ -24,7 +23,6 @@ import { debounce, isEmpty } from 'lodash'
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import AssistantSettings from './AssistantSettings'
import SendMessageSetting from './SendMessageSetting'
import { DEFAULT_CONEXTCOUNT } from '@renderer/config/constant'
@ -35,7 +33,6 @@ interface Props {
const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
const [text, setText] = useState('')
const { toggleRightSidebar } = useShowRightSidebar()
const { addTopic } = useAssistant(assistant.id)
const { sendMessageShortcut, showInputEstimatedTokens } = useSettings()
const [expended, setExpend] = useState(false)
@ -104,6 +101,7 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
if (!generating) {
if ((e.ctrlKey || e.metaKey) && e.key === 'n') {
addNewTopic()
EventEmitter.emit(EVENT_NAMES.SHOW_TOPIC_SIDEBAR)
inputRef.current?.focus()
}
}
@ -137,11 +135,6 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
<PlusCircleOutlined />
</ToolbarButton>
</Tooltip>
<Tooltip placement="top" title={t('assistant.input.topics')} arrow>
<ToolbarButton type="text" onClick={toggleRightSidebar}>
<HistoryOutlined />
</ToolbarButton>
</Tooltip>
<Tooltip placement="top" title={t('assistant.input.clear')} arrow>
<Popconfirm
icon={false}
@ -155,11 +148,16 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
</ToolbarButton>
</Popconfirm>
</Tooltip>
<AssistantSettings assistant={assistant}>
<ToolbarButton type="text">
<Tooltip placement="top" title={t('assistant.input.topics')} arrow>
<ToolbarButton type="text" onClick={() => EventEmitter.emit(EVENT_NAMES.SHOW_TOPIC_SIDEBAR)}>
<HistoryOutlined />
</ToolbarButton>
</Tooltip>
<Tooltip placement="top" title={t('assistant.input.settings')} arrow>
<ToolbarButton type="text" onClick={() => EventEmitter.emit(EVENT_NAMES.SHOW_CHAT_SETTINGS)}>
<ControlOutlined />
</ToolbarButton>
</AssistantSettings>
</Tooltip>
<Tooltip placement="top" title={expended ? t('assistant.input.collapse') : t('assistant.input.expand')} arrow>
<ToolbarButton type="text" onClick={() => setExpend(!expended)}>
{expended ? <FullscreenExitOutlined /> : <FullscreenOutlined />}

View File

@ -0,0 +1,100 @@
import { Assistant, Topic } from '@renderer/types'
import { FC, useEffect, useState } from 'react'
import styled from 'styled-components'
import TopicsTab from './TopicsTab'
import SettingsTab from './SettingsTab'
import { useTranslation } from 'react-i18next'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
import { useShowRightSidebar } from '@renderer/hooks/useStore'
interface Props {
assistant: Assistant
activeTopic: Topic
setActiveTopic: (topic: Topic) => void
}
const RightSidebar: FC<Props> = (props) => {
const [tab, setTab] = useState<'topic' | 'settings'>('topic')
const { rightSidebarShown, showRightSidebar, hideRightSidebar } = useShowRightSidebar()
const { t } = useTranslation()
const isTopicTab = tab === 'topic'
const isSettingsTab = tab === 'settings'
useEffect(() => {
const unsubscribes = [
EventEmitter.on(EVENT_NAMES.SHOW_TOPIC_SIDEBAR, (): any => {
if (rightSidebarShown && isTopicTab) {
return hideRightSidebar()
}
if (rightSidebarShown) {
return setTab('topic')
}
showRightSidebar()
setTab('topic')
}),
EventEmitter.on(EVENT_NAMES.SHOW_CHAT_SETTINGS, (): any => {
if (rightSidebarShown && isSettingsTab) {
return hideRightSidebar()
}
if (rightSidebarShown) {
return setTab('settings')
}
showRightSidebar()
setTab('settings')
})
]
return () => unsubscribes.forEach((unsub) => unsub())
}, [hideRightSidebar, isSettingsTab, isTopicTab, rightSidebarShown, showRightSidebar])
return (
<Container style={{ display: rightSidebarShown ? 'block' : 'none' }}>
<Tabs>
<Tab className={tab === 'topic' ? 'active' : ''} onClick={() => setTab('topic')}>
{t('common.topics')}
</Tab>
<Tab className={tab === 'settings' ? 'active' : ''} onClick={() => setTab('settings')}>
{t('settings.title')}
</Tab>
</Tabs>
{tab === 'topic' && <TopicsTab {...props} />}
{tab === 'settings' && <SettingsTab assistant={props.assistant} />}
</Container>
)
}
const Container = styled.div`
width: var(--topic-list-width);
height: 100%;
border-left: 0.5px solid var(--color-border);
overflow-y: auto;
.collapsed {
width: 0;
border-left: none;
}
`
const Tabs = styled.div`
display: flex;
flex-direction: row;
border-bottom: 1px solid var(--color-border);
padding: 0 10px;
`
const Tab = styled.div`
padding: 8px 0;
font-weight: 500;
display: flex;
flex: 1;
justify-content: center;
align-items: center;
font-size: 13px;
cursor: pointer;
color: #8a8a8a;
border-bottom: 1px solid transparent;
&.active {
color: white;
font-weight: 600;
}
`
export default RightSidebar

View File

@ -1,23 +1,31 @@
import { QuestionCircleOutlined } from '@ant-design/icons'
import { Assistant } from '@renderer/types'
import styled from 'styled-components'
import { DEFAULT_CONEXTCOUNT, DEFAULT_TEMPERATURE } from '@renderer/config/constant'
import { useAssistant } from '@renderer/hooks/useAssistant'
import { Assistant } from '@renderer/types'
import { Button, Col, InputNumber, Popover, Row, Slider, Tooltip } from 'antd'
import { Button, Col, InputNumber, Row, Slider, Switch, Tooltip } from 'antd'
import { debounce } from 'lodash'
import { FC, PropsWithChildren, useCallback, useEffect, useState } from 'react'
import { FC, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import { QuestionCircleOutlined } from '@ant-design/icons'
import { SettingDivider, SettingRow, SettingRowTitle, SettingSubtitle } from '@renderer/pages/settings/components'
import { useSettings } from '@renderer/hooks/useSettings'
import { useAppDispatch } from '@renderer/store'
import { setMessageFont, setShowInputEstimatedTokens, setShowMessageDivider } from '@renderer/store/settings'
interface Props {
assistant: Assistant
}
const PopoverContent: FC<Props> = (props) => {
const SettingsTab: FC<Props> = (props) => {
const { assistant, updateAssistantSettings, updateAssistant } = useAssistant(props.assistant.id)
const [temperature, setTemperature] = useState(assistant?.settings?.temperature ?? DEFAULT_TEMPERATURE)
const [contextCount, setConextCount] = useState(assistant?.settings?.contextCount ?? DEFAULT_CONEXTCOUNT)
const { t } = useTranslation()
const dispatch = useAppDispatch()
const { showMessageDivider, messageFont, showInputEstimatedTokens } = useSettings()
const onUpdateAssistantSettings = useCallback(
debounce(
({ _temperature, _contextCount }: { _temperature?: number; _contextCount?: number }) => {
@ -70,30 +78,29 @@ const PopoverContent: FC<Props> = (props) => {
return (
<Container>
<Row align="middle" style={{ marginBottom: 10 }} gutter={20}>
<Col span={6}>
<Row align="middle" justify="end">
<Label>{t('assistant.settings.temperature')}</Label>
<Tooltip title={t('assistant.settings.temperature.tip')}>
<QuestionIcon />
</Tooltip>
</Row>
</Col>
<Col span={14}>
<SettingSubtitle>{t('settings.messages.model.title')}</SettingSubtitle>
<SettingDivider />
<Row align="middle">
<Label>{t('assistant.settings.conext_count')}</Label>
<Tooltip title={t('assistant.settings.temperature.tip')}>
<QuestionIcon />
</Tooltip>
</Row>
<Row align="middle" gutter={10}>
<Col span={18}>
<Slider
min={0}
max={1.2}
onChange={onTemperatureChange}
value={typeof temperature === 'number' ? temperature : 0}
marks={{ 0: '0', 0.7: '0.7', 1: '1', 1.2: '1.2' }}
marks={{ 0: '0', 0.7: '0.7', 1.2: '1.2' }}
step={0.1}
/>
</Col>
<Col span={3}>
<InputNumber
<Col span={6}>
<InputNumberic
min={0}
max={1.2}
style={{ width: 50, marginLeft: 5, textAlign: 'center' }}
step={0.1}
value={temperature}
onChange={onTemperatureChange}
@ -101,16 +108,14 @@ const PopoverContent: FC<Props> = (props) => {
/>
</Col>
</Row>
<Row align="middle" style={{ marginBottom: 10 }} gutter={20}>
<Col span={6}>
<Row align="middle" justify="end">
<Label>{t('assistant.settings.conext_count')}</Label>
<Tooltip title={t('assistant.settings.conext_count.tip')}>
<QuestionIcon />
</Tooltip>
</Row>
</Col>
<Col span={14}>
<Row align="middle">
<Label>{t('assistant.settings.conext_count')}</Label>
<Tooltip title={t('assistant.settings.conext_count.tip')}>
<QuestionIcon />
</Tooltip>
</Row>
<Row align="middle" gutter={10}>
<Col span={18}>
<Slider
min={0}
max={20}
@ -120,11 +125,10 @@ const PopoverContent: FC<Props> = (props) => {
step={1}
/>
</Col>
<Col span={3}>
<InputNumber
<Col span={6}>
<InputNumberic
min={0}
max={20}
style={{ width: 50, marginLeft: 5, textAlign: 'center' }}
step={1}
value={contextCount}
onChange={onConextCountChange}
@ -132,49 +136,63 @@ const PopoverContent: FC<Props> = (props) => {
/>
</Col>
</Row>
<Row justify="center">
<Button onClick={onReset}>{t('assistant.settings.reset')}</Button>
</Row>
<Button onClick={onReset} style={{ width: '100%' }}>
{t('assistant.settings.reset')}
</Button>
<SettingSubtitle>{t('settings.messages.title')}</SettingSubtitle>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.messages.divider')}</SettingRowTitle>
<Switch checked={showMessageDivider} onChange={(checked) => dispatch(setShowMessageDivider(checked))} />
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.messages.use_serif_font')}</SettingRowTitle>
<Switch
checked={messageFont === 'serif'}
onChange={(checked) => dispatch(setMessageFont(checked ? 'serif' : 'system'))}
/>
</SettingRow>
<SettingDivider />
<SettingSubtitle style={{ marginTop: 20 }}>{t('settings.messages.input.title')}</SettingSubtitle>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.messages.input.show_estimated_tokens')}</SettingRowTitle>
<Switch
checked={showInputEstimatedTokens}
onChange={(checked) => dispatch(setShowInputEstimatedTokens(checked))}
/>
</SettingRow>
<SettingDivider />
</Container>
)
}
const AssistantSettings: FC<Props & PropsWithChildren> = ({ children, assistant }) => {
const [open, setOpen] = useState(false)
const { t } = useTranslation()
return (
<Popover content={<PopoverContent assistant={assistant} />} trigger="click" onOpenChange={setOpen}>
{open ? (
children
) : (
<Tooltip placement="top" title={t('assistant.input.settings')} arrow>
{children}
</Tooltip>
)}
</Popover>
)
}
const Container = styled.div`
display: flex;
flex-direction: column;
margin-bottom: 8px;
width: 420px;
padding: 5px;
padding: 0 10px;
`
const InputNumberic = styled(InputNumber)`
width: 45px;
padding: 0;
margin-left: 5px;
text-align: center;
.ant-input-number-input {
text-align: center;
}
`
const Label = styled.p`
margin: 0;
font-size: 14px;
font-size: 12px;
font-weight: bold;
margin-right: 5px;
margin-right: 8px;
`
const QuestionIcon = styled(QuestionCircleOutlined)`
font-size: 14px;
font-size: 12px;
cursor: pointer;
color: var(--color-text-3);
`
export default AssistantSettings
export default SettingsTab

View File

@ -3,7 +3,7 @@ import { useAssistant } from '@renderer/hooks/useAssistant'
import { useShowRightSidebar } from '@renderer/hooks/useStore'
import { fetchMessagesSummary } from '@renderer/services/api'
import { Assistant, Topic } from '@renderer/types'
import { Button, Dropdown, MenuProps, Popconfirm } from 'antd'
import { Dropdown, MenuProps } from 'antd'
import { FC } from 'react'
import styled from 'styled-components'
import { DeleteOutlined, EditOutlined, SignatureOutlined } from '@ant-design/icons'
@ -19,9 +19,9 @@ interface Props {
setActiveTopic: (topic: Topic) => void
}
const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic }) => {
const { showRightSidebar } = useShowRightSidebar()
const { assistant, removeTopic, updateTopic, removeAllTopics, updateTopics } = useAssistant(_assistant.id)
const TopicsTab: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic }) => {
const { rightSidebarShown } = useShowRightSidebar()
const { assistant, removeTopic, updateTopic, updateTopics } = useAssistant(_assistant.id)
const { t } = useTranslation()
const generating = useAppSelector((state) => state.runtime.generating)
@ -93,23 +93,7 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
}
return (
<Container style={{ display: showRightSidebar ? 'block' : 'none' }}>
<TopicTitle>
<span>
{t('assistant.topics.title')} ({assistant.topics.length})
</span>
<Popconfirm
icon={false}
title={t('assistant.topics.delete.all.title')}
description={t('assistant.topics.delete.all.content')}
placement="leftBottom"
onConfirm={removeAllTopics}
okType="danger">
<DeleteButton type="text">
<DeleteIcon />
</DeleteButton>
</Popconfirm>
</TopicTitle>
<Container style={{ display: rightSidebarShown ? 'block' : 'none' }}>
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable">
{(provided) => (
@ -138,15 +122,7 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
}
const Container = styled.div`
width: var(--topic-list-width);
height: 100%;
border-left: 0.5px solid var(--color-border);
padding: 10px;
overflow-y: auto;
&.collapsed {
width: 0;
border-left: none;
}
padding: 15px 10px;
`
const TopicListItem = styled.div`
@ -166,31 +142,4 @@ const TopicListItem = styled.div`
}
`
const TopicTitle = styled.div`
font-weight: bold;
margin-bottom: 10px;
font-size: 14px;
color: var(--color-text-1);
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
`
const DeleteButton = styled(Button)`
width: 30px;
height: 30px;
border-radius: 50%;
padding: 0;
&:hover {
.anticon {
color: #ff4d4f;
}
}
`
const DeleteIcon = styled(DeleteOutlined)`
font-size: 16px;
`
export default Topics
export default TopicsTab

View File

@ -1,6 +1,6 @@
import { FC, useState } from 'react'
import { SettingContainer, SettingDivider, SettingRow, SettingRowTitle, SettingTitle } from './components'
import { Avatar, Input, Select, Switch, Upload } from 'antd'
import { Avatar, Input, Select, Upload } from 'antd'
import styled from 'styled-components'
import LocalStorage from '@renderer/services/storage'
import { compressImage, isValidProxyUrl } from '@renderer/utils'
@ -8,27 +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,
setMessageFont,
setShowInputEstimatedTokens,
setShowMessageDivider,
setUserName
} from '@renderer/store/settings'
import { setLanguage, 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,
messageFont,
showInputEstimatedTokens
} = useSettings()
const { language, proxyUrl: storeProxyUrl, userName } = useSettings()
const [proxyUrl, setProxyUrl] = useState<string | undefined>(storeProxyUrl)
const dispatch = useAppDispatch()
const { t } = useTranslation()
@ -110,31 +97,6 @@ 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 />
<SettingTitle style={{ marginTop: 20 }}>{t('settings.general.input.title')}</SettingTitle>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.general.input.show_estimated_tokens')}</SettingRowTitle>
<Switch
checked={showInputEstimatedTokens}
onChange={(checked) => dispatch(setShowInputEstimatedTokens(checked))}
/>
</SettingRow>
<SettingDivider />
</SettingContainer>
)
}

View File

@ -39,10 +39,10 @@ export const SettingRow = styled.div`
flex-direction: row;
justify-content: space-between;
align-items: center;
min-height: 40px;
`
export const SettingRowTitle = styled.div`
font-size: 14px;
line-height: 18px;
color: var(--color-text-1);
`

View File

@ -11,5 +11,7 @@ export const EVENT_NAMES = {
EDIT_MESSAGE: 'EDIT_MESSAGE',
REGENERATE_MESSAGE: 'REGENERATE_MESSAGE',
CHAT_COMPLETION_PAUSED: 'CHAT_COMPLETION_PAUSED',
ESTIMATED_TOKEN_COUNT: 'ESTIMATED_TOKEN_COUNT'
ESTIMATED_TOKEN_COUNT: 'ESTIMATED_TOKEN_COUNT',
SHOW_CHAT_SETTINGS: 'SHOW_CHAT_SETTINGS',
SHOW_TOPIC_SIDEBAR: 'SHOW_TOPIC_SIDEBAR'
}

View File

@ -33,6 +33,9 @@ const settingsSlice = createSlice({
toggleRightSidebar: (state) => {
state.showRightSidebar = !state.showRightSidebar
},
setShowRightSidebar: (state, action: PayloadAction<boolean>) => {
state.showRightSidebar = action.payload
},
toggleShowAssistants: (state) => {
state.showAssistants = !state.showAssistants
},
@ -61,6 +64,7 @@ const settingsSlice = createSlice({
})
export const {
setShowRightSidebar,
toggleRightSidebar,
toggleShowAssistants,
setSendMessageShortcut,