feat(Settings): implement assistant icon type selection and localization updates

This commit is contained in:
kangfenmao 2025-04-13 10:45:47 +08:00
parent 97ef7016d3
commit 41981acd77
11 changed files with 112 additions and 34 deletions

View File

@ -1,10 +1,11 @@
import store, { useAppDispatch, useAppSelector } from '@renderer/store'
import {
AssistantIconType,
SendMessageShortcut,
setAssistantIconType,
setLaunchOnBoot,
setLaunchToTray,
setSendMessageShortcut as _setSendMessageShortcut,
setShowAssistantIcon,
setSidebarIcons,
setTargetLanguage,
setTheme,
@ -70,8 +71,8 @@ export function useSettings() {
updateSidebarDisabledIcons(icons: SidebarIcon[]) {
dispatch(setSidebarIcons({ disabled: icons }))
},
setShowAssistantIcon(showAssistantIcon: boolean) {
dispatch(setShowAssistantIcon(showAssistantIcon))
setAssistantIconType(assistantIconType: AssistantIconType) {
dispatch(setAssistantIconType(assistantIconType))
}
}
}

View File

@ -43,6 +43,7 @@
"edit.title": "Edit Assistant",
"save.success": "Saved successfully",
"save.title": "Save to agent",
"icon.type": "Assistant Icon",
"search": "Search assistants...",
"settings.default_model": "Default Model",
"settings.knowledge_base": "Knowledge Base Settings",
@ -787,7 +788,10 @@
"advanced.title": "Advanced Settings",
"assistant": "Default Assistant",
"assistant.model_params": "Model Parameters",
"assistant.show.icon": "Show model icon",
"assistant.icon.type": "Model Icon Type",
"assistant.icon.type.model": "Model Icon",
"assistant.icon.type.emoji": "Emoji Icon",
"assistant.icon.type.none": "Hide",
"assistant.title": "Default Assistant",
"data": {
"app_data": "App Data",

View File

@ -43,6 +43,7 @@
"edit.title": "アシスタントを編集",
"save.success": "保存に成功しました",
"save.title": "エージェントに保存",
"icon.type": "アシスタントアイコン",
"search": "アシスタントを検索...",
"settings.mcp": "MCP サーバー",
"settings.mcp.enableFirst": "まず MCP 設定でこのサーバーを有効にしてください",
@ -787,7 +788,10 @@
"advanced.title": "詳細設定",
"assistant": "デフォルトアシスタント",
"assistant.model_params": "モデルパラメータ",
"assistant.show.icon": "モデルアイコンを表示",
"assistant.icon.type": "モデルアイコンタイプ",
"assistant.icon.type.model": "モデルアイコン",
"assistant.icon.type.emoji": "Emoji アイコン",
"assistant.icon.type.none": "表示しない",
"assistant.title": "デフォルトアシスタント",
"data": {
"app_data": "アプリデータ",

View File

@ -43,6 +43,7 @@
"edit.title": "Редактировать ассистента",
"save.success": "Успешно сохранено",
"save.title": "Сохранить в агента",
"icon.type": "Иконка ассистента",
"search": "Поиск ассистентов...",
"settings.mcp": "Серверы MCP",
"settings.mcp.enableFirst": "Сначала включите этот сервер в настройках MCP",
@ -787,7 +788,10 @@
"advanced.title": "Расширенные настройки",
"assistant": "Ассистент по умолчанию",
"assistant.model_params": "Параметры модели",
"assistant.show.icon": "Показывать модельный иконки",
"assistant.icon.type": "Тип модели иконки",
"assistant.icon.type.model": "Модель иконки",
"assistant.icon.type.emoji": "Emoji иконка",
"assistant.icon.type.none": "Не отображать",
"assistant.title": "Ассистент по умолчанию",
"data": {
"app_data": "Данные приложения",

View File

@ -43,6 +43,7 @@
"edit.title": "编辑助手",
"save.success": "保存成功",
"save.title": "保存到智能体",
"icon.type": "助手图标",
"search": "搜索助手",
"settings.mcp": "MCP 服务器",
"settings.mcp.enableFirst": "请先在 MCP 设置中启用此服务器",
@ -787,7 +788,10 @@
"advanced.title": "高级设置",
"assistant": "默认助手",
"assistant.model_params": "模型参数",
"assistant.show.icon": "显示模型图标",
"assistant.icon.type": "模型图标类型",
"assistant.icon.type.model": "模型图标",
"assistant.icon.type.emoji": "Emoji 表情",
"assistant.icon.type.none": "不显示",
"assistant.title": "默认助手",
"data": {
"app_data": "应用数据",

View File

@ -43,6 +43,7 @@
"edit.title": "編輯助手",
"save.success": "儲存成功",
"save.title": "儲存到智慧代理人",
"icon.type": "助手圖示",
"search": "搜尋助手...",
"settings.mcp": "MCP 伺服器",
"settings.mcp.enableFirst": "請先在 MCP 設定中啟用此伺服器",
@ -787,7 +788,10 @@
"advanced.title": "進階設定",
"assistant": "預設助手",
"assistant.model_params": "模型參數",
"assistant.show.icon": "顯示模型圖示",
"assistant.icon.type": "模型圖示類型",
"assistant.icon.type.model": "模型圖示",
"assistant.icon.type.emoji": "Emoji 表情",
"assistant.icon.type.none": "不顯示",
"assistant.title": "預設助手",
"data": {
"app_data": "應用程式資料",

View File

@ -3,6 +3,7 @@ import {
EditOutlined,
MinusCircleOutlined,
SaveOutlined,
SmileOutlined,
SortAscendingOutlined,
SortDescendingOutlined
} from '@ant-design/icons'
@ -39,7 +40,7 @@ interface AssistantItemProps {
const AssistantItem: FC<AssistantItemProps> = ({ assistant, isActive, onSwitch, onDelete, addAgent, addAssistant }) => {
const { t } = useTranslation()
const { removeAllTopics } = useAssistant(assistant.id) // 使用当前助手的ID
const { clickAssistantToShowTopic, topicPosition, showAssistantIcon } = useSettings()
const { clickAssistantToShowTopic, topicPosition, assistantIconType, setAssistantIconType } = useSettings()
const defaultModel = getDefaultModel()
const { assistants, updateAssistants } = useAssistants()
@ -119,6 +120,28 @@ const AssistantItem: FC<AssistantItemProps> = ({ assistant, isActive, onSwitch,
})
}
},
{
label: t('assistants.icon.type'),
key: 'icon-type',
icon: <SmileOutlined />,
children: [
{
label: t('settings.assistant.icon.type.model'),
key: 'model',
onClick: () => setAssistantIconType('model')
},
{
label: t('settings.assistant.icon.type.emoji'),
key: 'emoji',
onClick: () => setAssistantIconType('emoji')
},
{
label: t('settings.assistant.icon.type.none'),
key: 'none',
onClick: () => setAssistantIconType('none')
}
]
},
{ type: 'divider' },
{
label: t('common.sort.pinyin.asc'),
@ -174,18 +197,20 @@ const AssistantItem: FC<AssistantItemProps> = ({ assistant, isActive, onSwitch,
<Dropdown menu={{ items: getMenuItems(assistant) }} trigger={['contextMenu']}>
<Container onClick={handleSwitch} className={isActive ? 'active' : ''}>
<AssistantNameRow className="name" title={fullAssistantName}>
{showAssistantIcon ? (
{assistantIconType === 'model' ? (
<ModelAvatar
model={assistant.model || defaultModel}
size={22}
size={24}
className={isPending && !isActive ? 'animation-pulse' : ''}
/>
) : (
assistantIconType === 'emoji' && (
<AssistantEmoji
$emoji={assistant.emoji || assistantName.slice(0, 1)}
className={isPending && !isActive ? 'animation-pulse' : ''}>
{assistant.emoji || assistantName.slice(0, 1)}
</AssistantEmoji>
)
)}
<AssistantName className="text-nowrap">{assistantName}</AssistantName>
</AssistantNameRow>
@ -203,7 +228,8 @@ const Container = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 7px 10px;
padding: 0 10px;
height: 37px;
position: relative;
font-family: Ubuntu;
border-radius: var(--list-item-border-radius);
@ -231,20 +257,21 @@ const AssistantNameRow = styled.div`
display: flex;
flex-direction: row;
align-items: center;
gap: 5px;
gap: 8px;
`
const AssistantEmoji = styled.div<{ $emoji: string }>`
width: 22px;
height: 22px;
border-radius: 11px;
width: 26px;
height: 26px;
border-radius: 13px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
font-size: 12px;
font-size: 15px;
position: relative;
overflow: hidden;
margin-right: 3px;
&:before {
width: 100%;
height: 100%;
@ -261,7 +288,9 @@ const AssistantEmoji = styled.div<{ $emoji: string }>`
}
`
const AssistantName = styled.div``
const AssistantName = styled.div`
font-size: 13px;
`
const MenuButton = styled.div`
display: flex;

View File

@ -4,7 +4,9 @@ import { useTheme } from '@renderer/context/ThemeProvider'
import { useSettings } from '@renderer/hooks/useSettings'
import { useAppDispatch } from '@renderer/store'
import {
AssistantIconType,
DEFAULT_SIDEBAR_ICONS,
setAssistantIconType,
setClickAssistantToShowTopic,
setCustomCss,
setShowTopicTime,
@ -31,8 +33,7 @@ const DisplaySettings: FC = () => {
showTopicTime,
customCss,
sidebarIcons,
showAssistantIcon,
setShowAssistantIcon
assistantIconType
} = useSettings()
const { theme: themeMode } = useTheme()
const { t } = useTranslation()
@ -87,6 +88,15 @@ const DisplaySettings: FC = () => {
[t]
)
const assistantIconTypeOptions = useMemo(
() => [
{ value: 'model', label: t('settings.assistant.icon.type.model') },
{ value: 'emoji', label: t('settings.assistant.icon.type.emoji') },
{ value: 'none', label: t('settings.assistant.icon.type.none') }
],
[t]
)
return (
<SettingContainer theme={themeMode}>
<SettingGroup theme={theme}>
@ -143,8 +153,13 @@ const DisplaySettings: FC = () => {
<SettingTitle>{t('settings.display.assistant.title')}</SettingTitle>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.assistant.show.icon')}</SettingRowTitle>
<Switch checked={showAssistantIcon} onChange={(checked) => setShowAssistantIcon(checked)} />
<SettingRowTitle>{t('settings.assistant.icon.type')}</SettingRowTitle>
<Segmented
value={assistantIconType}
shape="round"
onChange={(value) => dispatch(setAssistantIconType(value as AssistantIconType))}
options={assistantIconTypeOptions}
/>
</SettingRow>
</SettingGroup>
<SettingGroup theme={theme}>

View File

@ -42,7 +42,7 @@ const persistedReducer = persistReducer(
{
key: 'cherry-studio',
storage,
version: 95,
version: 96,
blacklist: ['runtime', 'messages'],
migrate
},

View File

@ -1213,6 +1213,17 @@ const migrateConfig = {
} catch (error) {
return state
}
},
'96': (state: RootState) => {
try {
// @ts-ignore eslint-disable-next-line
state.settings.assistantIconType = state.settings?.showAssistantIcon ? 'model' : 'emoji'
// @ts-ignore eslint-disable-next-line
delete state.settings.showAssistantIcon
return state
} catch (error) {
return state
}
}
}

View File

@ -21,6 +21,8 @@ export const DEFAULT_SIDEBAR_ICONS: SidebarIcon[] = [
export interface NutstoreSyncRuntime extends WebDAVSyncState {}
export type AssistantIconType = 'model' | 'emoji' | 'none'
export interface SettingsState {
showAssistants: boolean
showTopics: boolean
@ -42,7 +44,7 @@ export interface SettingsState {
fontSize: number
topicPosition: 'left' | 'right'
showTopicTime: boolean
showAssistantIcon: boolean
assistantIconType: AssistantIconType
pasteLongTextAsFile: boolean
pasteLongTextThreshold: number
clickAssistantToShowTopic: boolean
@ -147,7 +149,7 @@ export const initialState: SettingsState = {
fontSize: 14,
topicPosition: 'left',
showTopicTime: false,
showAssistantIcon: false,
assistantIconType: 'emoji',
pasteLongTextAsFile: false,
pasteLongTextThreshold: 1500,
clickAssistantToShowTopic: true,
@ -294,8 +296,8 @@ const settingsSlice = createSlice({
setShowTopicTime: (state, action: PayloadAction<boolean>) => {
state.showTopicTime = action.payload
},
setShowAssistantIcon: (state, action: PayloadAction<boolean>) => {
state.showAssistantIcon = action.payload
setAssistantIconType: (state, action: PayloadAction<AssistantIconType>) => {
state.assistantIconType = action.payload
},
setPasteLongTextAsFile: (state, action: PayloadAction<boolean>) => {
state.pasteLongTextAsFile = action.payload
@ -508,7 +510,7 @@ export const {
setWindowStyle,
setTopicPosition,
setShowTopicTime,
setShowAssistantIcon,
setAssistantIconType,
setPasteLongTextAsFile,
setAutoCheckUpdate,
setRenderInputMessageAsMarkdown,