diff --git a/packages/plugins/theme-editor/src/client/components/ThemeCard.tsx b/packages/plugins/theme-editor/src/client/components/ThemeCard.tsx index ade153ea9..ba0eaad63 100644 --- a/packages/plugins/theme-editor/src/client/components/ThemeCard.tsx +++ b/packages/plugins/theme-editor/src/client/components/ThemeCard.tsx @@ -71,8 +71,15 @@ const ThemeCard = (props: Props) => { const [loading, setLoading] = React.useState(false); const currentThemeId = useCurrentThemeId(); const { t } = useTranslation(); + const { token } = useToken(); + + const isDefault = item.id === systemSettings?.data?.data?.options?.themeId; const handleDelete = useCallback(() => { + if (isDefault) { + return; + } + modal.confirm({ title: t('Delete theme'), content: t('Deletion is unrecoverable. Confirm deletion?'), @@ -94,6 +101,7 @@ const ThemeCard = (props: Props) => { }, [ api, currentUser?.data?.data?.systemSettings?.themeId, + isDefault, item, modal, onChange, @@ -197,6 +205,7 @@ const ThemeCard = (props: Props) => { > {t('User selectable')} { > {t('Default theme')} { }, ], }; - }, [ - handleSwitchDefault, - handleSwitchOptional, - item.id, - item.optional, - loading, - systemSettings?.data?.data?.options?.themeId, - t, - ]); + }, [handleSwitchDefault, handleSwitchOptional, isDefault, item.optional, loading, t]); const actions = useMemo(() => { return [ , - , + , , ]; - }, [handleDelete, handleEdit, menu]); + }, [handleDelete, handleEdit, isDefault, menu, token.colorTextDisabled]); const extra = useMemo(() => { if (item.id !== systemSettings?.data?.data?.options?.themeId && !item.optional) { @@ -294,7 +308,7 @@ const ThemeCard = (props: Props) => { { return data @@ -34,7 +36,7 @@ function Label() { value: item.id, }; }); - }, [data]); + }, [data, t]); useEffect(() => { if (!data) { @@ -42,6 +44,25 @@ function Label() { } }, []); + useEffect(() => { + const init = async () => { + // 当 themeId 为空时表示插件是第一次被启用 + if (themeId == null && data) { + const firstTheme = data[0]; + + try { + // 避免并发请求,在本地存储中容易出问题 + await updateSystemThemeSettings(firstTheme.id); + await updateUserThemeSettings(firstTheme.id); + } catch (err) { + error(err); + } + } + }; + + init(); + }, [themeId, updateSystemThemeSettings, updateUserThemeSettings, data, api, refresh]); + if (err) { error(err); return null; diff --git a/packages/plugins/theme-editor/src/client/locale/zh-CN.ts b/packages/plugins/theme-editor/src/client/locale/zh-CN.ts index f6993d83e..51fb1f33e 100644 --- a/packages/plugins/theme-editor/src/client/locale/zh-CN.ts +++ b/packages/plugins/theme-editor/src/client/locale/zh-CN.ts @@ -16,6 +16,12 @@ const locale = { 'Edit based on current theme': '基于当前主题进行编辑', 'Create a brand new theme': '创建一个全新的主题', + // 内置主题的名字 + 'Default theme of antd': 'antd 默认主题', + Dark: '暗黑', + Compact: '紧凑', + 'Compact dark': '紧凑暗黑', + // 主题编辑器 'Theme Editor': '主题编辑器', Save: '保存', diff --git a/packages/plugins/theme-editor/src/server/builtinThemes.ts b/packages/plugins/theme-editor/src/server/builtinThemes.ts new file mode 100644 index 000000000..2deb6e79d --- /dev/null +++ b/packages/plugins/theme-editor/src/server/builtinThemes.ts @@ -0,0 +1,41 @@ +import { ThemeItem } from '../types'; + +/** antd 默认主题 */ +export const antd: Omit = { + config: { + name: 'Default theme of antd', + }, + optional: true, + isBuiltIn: true, +}; + +export const dark: Omit = { + config: { + name: 'Dark', + // @ts-ignore + algorithm: 'darkAlgorithm', + }, + optional: true, + isBuiltIn: true, +}; + +export const compact: Omit = { + config: { + name: 'Compact', + // @ts-ignore + algorithm: 'compactAlgorithm', + }, + optional: true, + isBuiltIn: true, +}; + +/** 同时包含 `紧凑` 和 `暗黑` 两种模式 */ +export const compactDark: Omit = { + config: { + name: 'Compact dark', + // @ts-ignore + algorithm: ['compactAlgorithm', 'darkAlgorithm'], + }, + optional: true, + isBuiltIn: true, +}; diff --git a/packages/plugins/theme-editor/src/server/plugin.ts b/packages/plugins/theme-editor/src/server/plugin.ts index 2ed0d2a19..d5945a3c9 100644 --- a/packages/plugins/theme-editor/src/server/plugin.ts +++ b/packages/plugins/theme-editor/src/server/plugin.ts @@ -1,12 +1,16 @@ +import { Collection } from '@nocobase/database'; import { InstallOptions, Plugin } from '@nocobase/server'; +import { antd, compact, compactDark, dark } from './builtinThemes'; export class ThemeEditorPlugin extends Plugin { + theme: Collection; + afterAdd() {} beforeLoad() {} async load() { - this.db.collection({ + this.theme = this.db.collection({ name: 'themeConfig', fields: [ // 主题配置内容,一个 JSON 字符串 @@ -27,7 +31,13 @@ export class ThemeEditorPlugin extends Plugin { }); } - async install(options?: InstallOptions) {} + async install(options?: InstallOptions) { + if ((await this.theme.repository.count()) === 0) { + await this.theme.repository.create({ + values: [antd, dark, compact, compactDark], + }); + } + } async afterEnable() {}