diff --git a/package.json b/package.json index 5f772e83..a1afa583 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,6 @@ }, "dependencies": { "@ant-design/icons": "^5.3.7", - "@ant-design/pro-card": "^2.6.0", "@dnd-kit/core": "^6.1.0", "@dnd-kit/utilities": "^3.2.2", "@gltf-transform/core": "^3.10.1", diff --git a/src/constants/settings.ts b/src/constants/settings.ts index 11ad91c0..e218ec52 100644 --- a/src/constants/settings.ts +++ b/src/constants/settings.ts @@ -13,4 +13,5 @@ export const DEFAULT_SETTINGS: Config = { }, primaryColor: DEFAULT_PRIMARY_COLOR, avatar: DEFAULT_USER_AVATAR, + nickName: '', }; diff --git a/src/features/AvatarWithUpload/index.tsx b/src/features/AvatarWithUpload/index.tsx index 9154c9c0..421d525c 100644 --- a/src/features/AvatarWithUpload/index.tsx +++ b/src/features/AvatarWithUpload/index.tsx @@ -55,7 +55,7 @@ const AvatarWithUpload = memo(
void 0} maxCount={1}> { - return index === 0 ?
: ; + return index === 0 ? ( +
+ ) : ( + + ); }; interface VirtualizedListProps { diff --git a/src/features/Settings/common.tsx b/src/features/Settings/common.tsx index 5c745a65..fb2f2894 100644 --- a/src/features/Settings/common.tsx +++ b/src/features/Settings/common.tsx @@ -1,19 +1,14 @@ -import { CheckCard } from '@ant-design/pro-card'; -import { - Form, - FormGroup, - FormItem, - PrimaryColors, - Swatches, - findCustomThemeName, -} from '@lobehub/ui'; -import { App, Button, Segmented } from 'antd'; -import { ThemeMode, createStyles, useTheme } from 'antd-style'; +import { Form, FormGroup, FormItem } from '@lobehub/ui'; +import { App, Button, Input, Segmented } from 'antd'; +import { ThemeMode, createStyles } from 'antd-style'; import classNames from 'classnames'; -import { Monitor, Settings2 } from 'lucide-react'; +import { isEqual } from 'lodash-es'; +import { Monitor, Settings2, User2Icon } from 'lucide-react'; import React from 'react'; import AvatarWithUpload from '@/features/AvatarWithUpload'; +import ThemeSwatchesPrimary from '@/features/Settings/features/ThemeSwatchesPrimary'; +import { useSyncSettings } from '@/features/Settings/useSyncSettings'; import { useAgentStore } from '@/store/agent'; import { useConfigStore } from '@/store/config'; import { useSessionStore } from '@/store/session'; @@ -40,18 +35,17 @@ const useStyles = createStyles(({ css }) => ({ const CommonConfig = (props: CommonConfigProps) => { const { style, className } = props; const { styles } = useStyles(); - const [primaryColor, backgroundEffect] = useConfigStore((s) => [ - s.config.primaryColor, - s.config.backgroundEffect, - ]); + const [config, setConfig] = useConfigStore((s) => [s.config, s.setConfig], isEqual); const clearAgentStorage = useAgentStore((s) => s.clearAgentStorage); const [themeMode, setThemeMode] = useThemeStore((s) => [s.themeMode, s.setThemeMode]); - const setConfig = useConfigStore((s) => s.setConfig); - const theme = useTheme(); const clearSessions = useSessionStore((s) => s.clearSessions); const resetConfig = useConfigStore((s) => s.resetConfig); const { message, modal } = App.useApp(); + const [form] = Form.useForm(); + + useSyncSettings(form); + const handleClear = () => { modal.confirm({ cancelText: '取消', @@ -89,46 +83,53 @@ const CommonConfig = (props: CommonConfigProps) => { return (
-
- - + + + - - { - const name = findCustomThemeName('primary', color) as PrimaryColors; - setConfig({ primaryColor: name || '' }); + + { + setConfig({ nickName: e.target.value }); }} /> + + + + + - { + onChange={(value: ThemeMode) => { setThemeMode(value as ThemeMode); }} - size="small" - > - - - - + options={[ + { + label: '🔆 亮色模式', + value: 'light', + }, + { + label: '🌙 暗色模式', + value: 'dark', + }, + { + label: '💻 跟随系统', + value: 'auto', + }, + ]} + /> { name={'backgroundEffect'} > { setConfig({ backgroundEffect: value }); }} diff --git a/src/features/Settings/features/ThemeSwatchesPrimary.tsx b/src/features/Settings/features/ThemeSwatchesPrimary.tsx new file mode 100644 index 00000000..026474bc --- /dev/null +++ b/src/features/Settings/features/ThemeSwatchesPrimary.tsx @@ -0,0 +1,29 @@ +import { + PrimaryColors, + Swatches, + findCustomThemeName, + primaryColors, + primaryColorsSwatches, +} from '@lobehub/ui'; +import { memo } from 'react'; + +import { useConfigStore } from '@/store/config'; + +const ThemeSwatchesPrimary = memo(() => { + const [primaryColor, setConfig] = useConfigStore((s) => [s.config.primaryColor, s.setConfig]); + + const handleSelect = (v: any) => { + const name = findCustomThemeName('primary', v) as PrimaryColors; + setConfig({ primaryColor: name || '' }); + }; + + return ( + + ); +}); + +export default ThemeSwatchesPrimary; diff --git a/src/features/Settings/useSyncSettings.ts b/src/features/Settings/useSyncSettings.ts new file mode 100644 index 00000000..c74d7179 --- /dev/null +++ b/src/features/Settings/useSyncSettings.ts @@ -0,0 +1,23 @@ +import { FormInstance } from 'antd/es/form/hooks/useForm'; +import { useEffect } from 'react'; + +import { useConfigStore } from '@/store/config'; + +export const useSyncSettings = (form: FormInstance) => { + useEffect(() => { + // set the first time + form.setFieldsValue(useConfigStore.getState().config); + + // sync with later updated settings + const unsubscribe = useConfigStore.subscribe( + (s) => s.config, + (config) => { + form.setFieldsValue(config); + }, + ); + + return () => { + unsubscribe(); + }; + }, []); +}; diff --git a/src/store/config/index.ts b/src/store/config/index.ts index b4193556..357fd7d0 100644 --- a/src/store/config/index.ts +++ b/src/store/config/index.ts @@ -1,6 +1,6 @@ import { produce } from 'immer'; import { isEqual, merge } from 'lodash-es'; -import { devtools, persist } from 'zustand/middleware'; +import { devtools, persist, subscribeWithSelector } from 'zustand/middleware'; import { shallow } from 'zustand/shallow'; import { createWithEqualityFn } from 'zustand/traditional'; import { StateCreator } from 'zustand/vanilla'; @@ -106,11 +106,13 @@ const createStore: StateCreator = (s }); export const useConfigStore = createWithEqualityFn()( - persist( - devtools(createStore, { - name: 'VIDOL_CONFIG_STORE', - }), - { name: CONFIG_STORAGE_KEY }, + subscribeWithSelector( + persist( + devtools(createStore, { + name: 'VIDOL_CONFIG_STORE', + }), + { name: CONFIG_STORAGE_KEY }, + ), ), shallow, ); diff --git a/src/store/session/selectors.ts b/src/store/session/selectors.ts index ac31df28..79c82e53 100644 --- a/src/store/session/selectors.ts +++ b/src/store/session/selectors.ts @@ -64,12 +64,13 @@ const currentChats = (s: SessionStore): ChatMessage[] => { const { messages } = session; return messages?.map((message) => { const userAvatar = useConfigStore.getState().config.avatar; + const userNickName = useConfigStore.getState().config.nickName; return { ...message, meta: { avatar: message.role === 'user' ? (userAvatar ? userAvatar : DEFAULT_USER_AVATAR) : avatar, description: message.role === 'user' ? undefined : description, - title: message.role === 'user' ? '你' : name, + title: message.role === 'user' ? (userNickName ? userNickName : '你') : name, }, }; }); diff --git a/src/types/config.ts b/src/types/config.ts index 1aa194a3..98a63cef 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -24,11 +24,18 @@ export interface PanelConfig { export type PanelKey = keyof PanelConfig; export interface CommonConfig { + /** + * 用户头像 + */ avatar: string; /** * 背景类型 */ backgroundEffect: BackgroundEffect; + /** + * 用户昵称 + */ + nickName: string; /** * 主题色 */