From 257f1183fc97333ecc1e3ee14ee43ad73f4c811f Mon Sep 17 00:00:00 2001
From: Azir-11 <2075125282@qq.com>
Date: Thu, 21 Aug 2025 19:14:15 +0800
Subject: [PATCH] feat(projects): support theme preset function.
---
src/layouts/modules/theme-drawer/index.vue | 3 +
.../theme-drawer/modules/preset/index.vue | 15 ++
.../modules/preset/modules/theme-preset.vue | 148 ++++++++++++++++++
src/locales/langs/en-us.ts | 26 ++-
src/locales/langs/zh-cn.ts | 26 ++-
src/theme/preset/azir.json | 90 +++++++++++
src/theme/preset/compact.json | 90 +++++++++++
src/theme/preset/dark.json | 90 +++++++++++
src/theme/preset/default.json | 90 +++++++++++
src/typings/app.d.ts | 12 ++
src/typings/components.d.ts | 2 +
11 files changed, 588 insertions(+), 4 deletions(-)
create mode 100644 src/layouts/modules/theme-drawer/modules/preset/index.vue
create mode 100644 src/layouts/modules/theme-drawer/modules/preset/modules/theme-preset.vue
create mode 100644 src/theme/preset/azir.json
create mode 100644 src/theme/preset/compact.json
create mode 100644 src/theme/preset/dark.json
create mode 100644 src/theme/preset/default.json
diff --git a/src/layouts/modules/theme-drawer/index.vue b/src/layouts/modules/theme-drawer/index.vue
index b963ba18..b8746711 100644
--- a/src/layouts/modules/theme-drawer/index.vue
+++ b/src/layouts/modules/theme-drawer/index.vue
@@ -6,6 +6,7 @@ import AppearanceSettings from './modules/appearance/index.vue';
import LayoutSettings from './modules/layout/index.vue';
import GeneralSettings from './modules/general/index.vue';
import ConfigOperation from './modules/config-operation.vue';
+import PresetSettings from './modules/preset/index.vue';
defineOptions({
name: 'ThemeDrawer'
@@ -33,6 +34,7 @@ const drawerWidth = computed(() => {
+
@@ -40,6 +42,7 @@ const drawerWidth = computed(() => {
+
diff --git a/src/layouts/modules/theme-drawer/modules/preset/index.vue b/src/layouts/modules/theme-drawer/modules/preset/index.vue
new file mode 100644
index 00000000..32e9251e
--- /dev/null
+++ b/src/layouts/modules/theme-drawer/modules/preset/index.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/layouts/modules/theme-drawer/modules/preset/modules/theme-preset.vue b/src/layouts/modules/theme-drawer/modules/preset/modules/theme-preset.vue
new file mode 100644
index 00000000..09defb59
--- /dev/null
+++ b/src/layouts/modules/theme-drawer/modules/preset/modules/theme-preset.vue
@@ -0,0 +1,148 @@
+
+
+
+ {{ $t('theme.appearance.preset.title') }}
+
+
+
+
+
+
+ {{ getPresetName(preset) }}
+
+
+
+
+ {{ $t('theme.appearance.preset.apply') }}
+
+
+
+
{{ getPresetDesc(preset) }}
+
+
+
+
+
+ {{ preset.themeScheme === 'dark' ? '🌙' : '☀️' }}
+
+
+ {{ preset.grayscale ? '🎨' : '' }}
+
+
+
+
+
+
diff --git a/src/locales/langs/en-us.ts b/src/locales/langs/en-us.ts
index ae721396..48c1e56a 100644
--- a/src/locales/langs/en-us.ts
+++ b/src/locales/langs/en-us.ts
@@ -62,7 +62,8 @@ const local: App.I18n.Schema = {
tabs: {
appearance: 'Appearance',
layout: 'Layout',
- general: 'General'
+ general: 'General',
+ preset: 'Preset'
},
appearance: {
themeSchema: {
@@ -83,7 +84,28 @@ const local: App.I18n.Schema = {
followPrimary: 'Follow Primary'
},
recommendColor: 'Apply Recommended Color Algorithm',
- recommendColorDesc: 'The recommended color algorithm refers to'
+ recommendColorDesc: 'The recommended color algorithm refers to',
+ preset: {
+ title: 'Theme Presets',
+ apply: 'Apply',
+ applySuccess: 'Preset applied successfully',
+ default: {
+ name: 'Default Preset',
+ desc: 'Default theme preset with balanced settings'
+ },
+ dark: {
+ name: 'Dark Preset',
+ desc: 'Dark theme preset for night time usage'
+ },
+ compact: {
+ name: 'Compact Preset',
+ desc: 'Compact layout preset for small screens'
+ },
+ azir: {
+ name: "Azir's Preset",
+ desc: 'It is a cold and elegant preset that Azir likes'
+ }
+ }
},
layout: {
layoutMode: {
diff --git a/src/locales/langs/zh-cn.ts b/src/locales/langs/zh-cn.ts
index 342f1c60..01c21a3e 100644
--- a/src/locales/langs/zh-cn.ts
+++ b/src/locales/langs/zh-cn.ts
@@ -62,7 +62,8 @@ const local: App.I18n.Schema = {
tabs: {
appearance: '外观',
layout: '布局',
- general: '通用'
+ general: '通用',
+ preset: '预设'
},
appearance: {
themeSchema: {
@@ -83,7 +84,28 @@ const local: App.I18n.Schema = {
followPrimary: '跟随主色'
},
recommendColor: '应用推荐算法的颜色',
- recommendColorDesc: '推荐颜色的算法参照'
+ recommendColorDesc: '推荐颜色的算法参照',
+ preset: {
+ title: '主题预设',
+ apply: '应用',
+ applySuccess: '预设应用成功',
+ default: {
+ name: '默认预设',
+ desc: 'Soybean 默认主题预设'
+ },
+ dark: {
+ name: '暗色预设',
+ desc: '适用于夜间使用的暗色主题预设'
+ },
+ compact: {
+ name: '紧凑型',
+ desc: '适用于小屏幕的紧凑布局预设'
+ },
+ azir: {
+ name: 'Azir的预设',
+ desc: '是 Azir 比较喜欢的莫兰迪色系冷淡风'
+ }
+ }
},
layout: {
layoutMode: {
diff --git a/src/theme/preset/azir.json b/src/theme/preset/azir.json
new file mode 100644
index 00000000..88ea182f
--- /dev/null
+++ b/src/theme/preset/azir.json
@@ -0,0 +1,90 @@
+{
+ "name": "Azir's Preset",
+ "desc": "It is a cold and elegant preset that Azir likes",
+ "i18nkey": "theme.appearance.preset.azir",
+ "version": "1.0.0",
+ "themeScheme": "light",
+ "grayscale": false,
+ "colourWeakness": false,
+ "recommendColor": true,
+ "themeColor": "#78a878",
+ "otherColor": {
+ "info": "#89b989",
+ "success": "#99c299",
+ "warning": "#d4bb9d",
+ "error": "#c49a9a"
+ },
+ "isInfoFollowPrimary": true,
+ "resetCacheStrategy": "refresh",
+ "layout": {
+ "mode": "vertical-mix",
+ "scrollMode": "wrapper"
+ },
+ "page": {
+ "animate": true,
+ "animateMode": "zoom-fade"
+ },
+ "header": {
+ "height": 64,
+ "breadcrumb": {
+ "visible": true,
+ "showIcon": true
+ },
+ "multilingual": {
+ "visible": true
+ },
+ "globalSearch": {
+ "visible": true
+ }
+ },
+ "tab": {
+ "visible": true,
+ "cache": true,
+ "height": 48,
+ "mode": "chrome"
+ },
+ "fixedHeaderAndTab": true,
+ "sider": {
+ "inverted": false,
+ "width": 220,
+ "collapsedWidth": 64,
+ "mixWidth": 90,
+ "mixCollapsedWidth": 64,
+ "mixChildMenuWidth": 200
+ },
+ "footer": {
+ "visible": true,
+ "fixed": true,
+ "height": 56,
+ "right": true
+ },
+ "watermark": {
+ "visible": false,
+ "text": "SoybeanAdmin",
+ "enableUserName": false,
+ "enableTime": true,
+ "timeFormat": "YYYY-MM-DD HH:mm:ss"
+ },
+ "tokens": {
+ "light": {
+ "colors": {
+ "container": "rgb(255, 255, 255)",
+ "layout": "rgb(247, 250, 252)",
+ "inverted": "rgb(0, 20, 40)",
+ "base-text": "rgb(31, 31, 31)"
+ },
+ "boxShadow": {
+ "header": "0 1px 2px rgb(0, 21, 41, 0.08)",
+ "sider": "2px 0 8px 0 rgb(29, 35, 41, 0.05)",
+ "tab": "0 1px 2px rgb(0, 21, 41, 0.08)"
+ }
+ },
+ "dark": {
+ "colors": {
+ "container": "rgb(28, 28, 28)",
+ "layout": "rgb(18, 18, 18)",
+ "base-text": "rgb(224, 224, 224)"
+ }
+ }
+ }
+}
diff --git a/src/theme/preset/compact.json b/src/theme/preset/compact.json
new file mode 100644
index 00000000..c89e83f6
--- /dev/null
+++ b/src/theme/preset/compact.json
@@ -0,0 +1,90 @@
+{
+ "name": "Compact Preset",
+ "desc": "Compact layout preset for small screens",
+ "i18nkey": "theme.appearance.preset.compact",
+ "version": "1.0.0",
+ "themeScheme": "light",
+ "grayscale": false,
+ "colourWeakness": false,
+ "recommendColor": false,
+ "themeColor": "#646cff",
+ "otherColor": {
+ "info": "#2080f0",
+ "success": "#52c41a",
+ "warning": "#faad14",
+ "error": "#f5222d"
+ },
+ "isInfoFollowPrimary": true,
+ "resetCacheStrategy": "close",
+ "layout": {
+ "mode": "vertical",
+ "scrollMode": "content"
+ },
+ "page": {
+ "animate": true,
+ "animateMode": "fade-slide"
+ },
+ "header": {
+ "height": 48,
+ "breadcrumb": {
+ "visible": true,
+ "showIcon": true
+ },
+ "multilingual": {
+ "visible": false
+ },
+ "globalSearch": {
+ "visible": false
+ }
+ },
+ "tab": {
+ "visible": true,
+ "cache": true,
+ "height": 36,
+ "mode": "button"
+ },
+ "fixedHeaderAndTab": true,
+ "sider": {
+ "inverted": false,
+ "width": 180,
+ "collapsedWidth": 48,
+ "mixWidth": 80,
+ "mixCollapsedWidth": 48,
+ "mixChildMenuWidth": 180
+ },
+ "footer": {
+ "visible": false,
+ "fixed": false,
+ "height": 40,
+ "right": true
+ },
+ "watermark": {
+ "visible": false,
+ "text": "SoybeanAdmin",
+ "enableUserName": false,
+ "enableTime": false,
+ "timeFormat": "YYYY-MM-DD HH:mm"
+ },
+ "tokens": {
+ "light": {
+ "colors": {
+ "container": "rgb(255, 255, 255)",
+ "layout": "rgb(247, 250, 252)",
+ "inverted": "rgb(0, 20, 40)",
+ "base-text": "rgb(31, 31, 31)"
+ },
+ "boxShadow": {
+ "header": "0 1px 2px rgb(0, 21, 41, 0.08)",
+ "sider": "2px 0 8px 0 rgb(29, 35, 41, 0.05)",
+ "tab": "0 1px 2px rgb(0, 21, 41, 0.08)"
+ }
+ },
+ "dark": {
+ "colors": {
+ "container": "rgb(28, 28, 28)",
+ "layout": "rgb(18, 18, 18)",
+ "base-text": "rgb(224, 224, 224)"
+ }
+ }
+ }
+}
diff --git a/src/theme/preset/dark.json b/src/theme/preset/dark.json
new file mode 100644
index 00000000..b5c50db1
--- /dev/null
+++ b/src/theme/preset/dark.json
@@ -0,0 +1,90 @@
+{
+ "name": "Dark Preset",
+ "desc": "Dark theme preset for night time usage",
+ "i18nkey": "theme.appearance.preset.dark",
+ "version": "1.0.0",
+ "themeScheme": "dark",
+ "grayscale": false,
+ "colourWeakness": false,
+ "recommendColor": false,
+ "themeColor": "#409eff",
+ "otherColor": {
+ "info": "#2080f0",
+ "success": "#52c41a",
+ "warning": "#faad14",
+ "error": "#f5222d"
+ },
+ "isInfoFollowPrimary": true,
+ "resetCacheStrategy": "close",
+ "layout": {
+ "mode": "vertical",
+ "scrollMode": "content"
+ },
+ "page": {
+ "animate": true,
+ "animateMode": "fade-slide"
+ },
+ "header": {
+ "height": 56,
+ "breadcrumb": {
+ "visible": true,
+ "showIcon": true
+ },
+ "multilingual": {
+ "visible": true
+ },
+ "globalSearch": {
+ "visible": true
+ }
+ },
+ "tab": {
+ "visible": true,
+ "cache": true,
+ "height": 44,
+ "mode": "chrome"
+ },
+ "fixedHeaderAndTab": true,
+ "sider": {
+ "inverted": true,
+ "width": 220,
+ "collapsedWidth": 64,
+ "mixWidth": 90,
+ "mixCollapsedWidth": 64,
+ "mixChildMenuWidth": 200
+ },
+ "footer": {
+ "visible": true,
+ "fixed": false,
+ "height": 48,
+ "right": true
+ },
+ "watermark": {
+ "visible": false,
+ "text": "SoybeanAdmin",
+ "enableUserName": false,
+ "enableTime": false,
+ "timeFormat": "YYYY-MM-DD HH:mm"
+ },
+ "tokens": {
+ "light": {
+ "colors": {
+ "container": "rgb(255, 255, 255)",
+ "layout": "rgb(247, 250, 252)",
+ "inverted": "rgb(0, 20, 40)",
+ "base-text": "rgb(31, 31, 31)"
+ },
+ "boxShadow": {
+ "header": "0 1px 2px rgb(0, 21, 41, 0.08)",
+ "sider": "2px 0 8px 0 rgb(29, 35, 41, 0.05)",
+ "tab": "0 1px 2px rgb(0, 21, 41, 0.08)"
+ }
+ },
+ "dark": {
+ "colors": {
+ "container": "rgb(28, 28, 28)",
+ "layout": "rgb(18, 18, 18)",
+ "base-text": "rgb(224, 224, 224)"
+ }
+ }
+ }
+}
diff --git a/src/theme/preset/default.json b/src/theme/preset/default.json
new file mode 100644
index 00000000..643fef4b
--- /dev/null
+++ b/src/theme/preset/default.json
@@ -0,0 +1,90 @@
+{
+ "name": "default",
+ "desc": "Default theme preset with balanced settings",
+ "i18nkey": "theme.appearance.preset.default",
+ "version": "1.0.0",
+ "themeScheme": "light",
+ "grayscale": false,
+ "colourWeakness": false,
+ "recommendColor": false,
+ "themeColor": "#646cff",
+ "otherColor": {
+ "info": "#2080f0",
+ "success": "#52c41a",
+ "warning": "#faad14",
+ "error": "#f5222d"
+ },
+ "isInfoFollowPrimary": true,
+ "resetCacheStrategy": "close",
+ "layout": {
+ "mode": "vertical",
+ "scrollMode": "content"
+ },
+ "page": {
+ "animate": true,
+ "animateMode": "fade-slide"
+ },
+ "header": {
+ "height": 56,
+ "breadcrumb": {
+ "visible": true,
+ "showIcon": true
+ },
+ "multilingual": {
+ "visible": true
+ },
+ "globalSearch": {
+ "visible": true
+ }
+ },
+ "tab": {
+ "visible": true,
+ "cache": true,
+ "height": 44,
+ "mode": "chrome"
+ },
+ "fixedHeaderAndTab": true,
+ "sider": {
+ "inverted": false,
+ "width": 220,
+ "collapsedWidth": 64,
+ "mixWidth": 90,
+ "mixCollapsedWidth": 64,
+ "mixChildMenuWidth": 200
+ },
+ "footer": {
+ "visible": true,
+ "fixed": false,
+ "height": 48,
+ "right": true
+ },
+ "watermark": {
+ "visible": false,
+ "text": "SoybeanAdmin",
+ "enableUserName": false,
+ "enableTime": false,
+ "timeFormat": "YYYY-MM-DD HH:mm"
+ },
+ "tokens": {
+ "light": {
+ "colors": {
+ "container": "rgb(255, 255, 255)",
+ "layout": "rgb(247, 250, 252)",
+ "inverted": "rgb(0, 20, 40)",
+ "base-text": "rgb(31, 31, 31)"
+ },
+ "boxShadow": {
+ "header": "0 1px 2px rgb(0, 21, 41, 0.08)",
+ "sider": "2px 0 8px 0 rgb(29, 35, 41, 0.05)",
+ "tab": "0 1px 2px rgb(0, 21, 41, 0.08)"
+ }
+ },
+ "dark": {
+ "colors": {
+ "container": "rgb(28, 28, 28)",
+ "layout": "rgb(18, 18, 18)",
+ "base-text": "rgb(224, 224, 224)"
+ }
+ }
+ }
+}
diff --git a/src/typings/app.d.ts b/src/typings/app.d.ts
index dc2c8c7f..084445f6 100644
--- a/src/typings/app.d.ts
+++ b/src/typings/app.d.ts
@@ -367,6 +367,7 @@ declare namespace App {
appearance: string;
layout: string;
general: string;
+ preset: string;
};
appearance: {
themeSchema: { title: string } & Record;
@@ -378,6 +379,17 @@ declare namespace App {
} & Theme.ThemeColor;
recommendColor: string;
recommendColorDesc: string;
+ preset: {
+ title: string;
+ apply: string;
+ applySuccess: string;
+ [key: string]:
+ | {
+ name: string;
+ desc: string;
+ }
+ | string;
+ };
};
layout: {
layoutMode: { title: string } & Record & {
diff --git a/src/typings/components.d.ts b/src/typings/components.d.ts
index 6662146a..1fe5130d 100644
--- a/src/typings/components.d.ts
+++ b/src/typings/components.d.ts
@@ -31,6 +31,7 @@ declare module 'vue' {
LookForward: typeof import('./../components/custom/look-forward.vue')['default']
MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']
NAlert: typeof import('naive-ui')['NAlert']
+ NBadge: typeof import('naive-ui')['NBadge']
NBreadcrumb: typeof import('naive-ui')['NBreadcrumb']
NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem']
NButton: typeof import('naive-ui')['NButton']
@@ -65,6 +66,7 @@ declare module 'vue' {
NSwitch: typeof import('naive-ui')['NSwitch']
NTab: typeof import('naive-ui')['NTab']
NTabs: typeof import('naive-ui')['NTabs']
+ NTag: typeof import('naive-ui')['NTag']
NThing: typeof import('naive-ui')['NThing']
NTooltip: typeof import('naive-ui')['NTooltip']
NWatermark: typeof import('naive-ui')['NWatermark']