Browse Source

feat: support custom background colors for sidebar and header (#4151)

* feat: support custom background colors for sidebar and header

* fix: type error
Vben 7 months ago
parent
commit
8f40d5107c

+ 1 - 1
apps/backend-mock/README.md

@@ -2,7 +2,7 @@
 
 ## Description
 
-Vben Admin 数据 mock 服务,没有对接任何的数据库,所有数据都是模拟的,用于前端开发时提供数据支持。由于 sqlite 安装需要在本地进行编译,所以这里接口是直接返回的。线上环境不再提供mock集成,可自行部署服务或者对接真实数据,同步 mock.js等工具有一些限制,比如上传文件不行、无法模拟复杂的逻辑等,所以这里使用了 真是的后端服务来实现。唯一麻烦的是本地需要同时启动后端服务和前端服务,但是这样可以更好的模拟真实环境。
+Vben Admin 数据 mock 服务,没有对接任何的数据库,所有数据都是模拟的,用于前端开发时提供数据支持。线上环境不再提供mock集成,可自行部署服务或者对接真实数据,mock.js 等工具有一些限制,比如上传文件不行、无法模拟复杂的逻辑等,所以这里使用了真实的后端服务来实现。唯一麻烦的是本地需要同时启动后端服务和前端服务,但是这样可以更好的模拟真实环境。
 
 ## Running the app
 

+ 3 - 0
docs/src/guide/essentials/settings.md

@@ -260,6 +260,7 @@ const defaultPreferences: Preferences = {
     colorWarning: 'hsl(42 84% 61%)',
     mode: 'dark',
     radius: '0.5',
+    semiDarkHeader: false,
     semiDarkMenu: true,
   },
   transition: {
@@ -452,6 +453,8 @@ interface ThemePreferences {
   mode: ThemeModeType;
   /** 圆角 */
   radius: string;
+  /** 是否开启半深色header(只在theme='light'时生效) */
+  semiDarkHeader: boolean;
   /** 是否开启半深色菜单(只在theme='light'时生效) */
   semiDarkMenu: boolean;
 }

+ 86 - 24
docs/src/guide/in-depth/theme.md

@@ -107,9 +107,6 @@ css 变量内的颜色,必须使用 `hsl` 格式,如 `0 0% 100%`,不需要
   /* 基本文字大小 */
   --font-size-base: 16px;
 
-  /* 主体内容背景色 */
-  --content: 240 11% 96%;
-
   /* =============component & UI============= */
 
   /* menu */
@@ -117,6 +114,9 @@ css 变量内的颜色,必须使用 `hsl` 格式,如 `0 0% 100%`,不需要
   --sidebar-deep: 210 11.11% 96.47%;
   --menu: var(--sidebar);
 
+  /* header */
+  --header: 0 0% 100%;
+
   accent-color: var(--primary);
   color-scheme: light;
 }
@@ -206,14 +206,12 @@ css 变量内的颜色,必须使用 `hsl` 格式,如 `0 0% 100%`,不需要
   /* 基本文字大小 */
   --font-size-base: 16px;
 
-  /* 主体内容背景色 */
-  --content: 240 11% 96%;
-
   /* =============component & UI============= */
 
   --sidebar: 222.34deg 10.43% 12.27%;
   --sidebar-deep: 220deg 13.06% 9%;
   --menu: var(--sidebar);
+  --header: 222.34deg 10.43% 12.27%;
 
   color-scheme: dark;
 }
@@ -228,7 +226,6 @@ css 变量内的颜色,必须使用 `hsl` 格式,如 `0 0% 100%`,不需要
 ### 默认主题下:
 
 ```css
-/*  */
 :root {
   /* Background color for <Card /> */
   --card: 0 0% 30%;
@@ -238,7 +235,6 @@ css 变量内的颜色,必须使用 `hsl` 格式,如 `0 0% 100%`,不需要
 ### 黑暗模式下
 
 ```css
-/*  */
 .dark,
 .dark[data-theme='custom'],
 .dark[data-theme='default'] {
@@ -335,7 +331,7 @@ type BuiltinThemeType =
 
   /* 主体区域背景色 */
   --background-deep: 210 11.11% 96.47%;
-  --foreground: 210 6% 21%;
+  --foreground: 222 84% 5%;
 
   /* Background color for <Card /> */
   --card: 0 0% 100%;
@@ -346,8 +342,12 @@ type BuiltinThemeType =
   --popover-foreground: 222.2 84% 4.9%;
 
   /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */
-  --muted: 210 40% 96.1%;
-  --muted-foreground: 215.4 16.3% 46.9%;
+
+  /* --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%; */
+
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
 
   /* 主题颜色 */
 
@@ -405,16 +405,16 @@ type BuiltinThemeType =
   /* 基本文字大小 */
   --font-size-base: 16px;
 
-  /* 主体内容背景色 */
-  --content: 240 11% 96%;
-
   /* =============component & UI============= */
 
   /* menu */
   --sidebar: 0 0% 100%;
-  --sidebar-deep: 210 11.11% 96.47%;
+  --sidebar-deep: 0 0% 100%;
   --menu: var(--sidebar);
 
+  /* header */
+  --header: 0 0% 100%;
+
   accent-color: var(--primary);
   color-scheme: light;
 }
@@ -719,8 +719,13 @@ type BuiltinThemeType =
   --popover-foreground: 210 40% 98%;
 
   /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */
-  --muted: 220deg 6.82% 17.25%;
-  --muted-foreground: 215 20.2% 65.1%;
+
+  /* --muted: 220deg 6.82% 17.25%; */
+
+  /* --muted-foreground: 215 20.2% 65.1%; */
+
+  --muted: 240 3.7% 15.9%;
+  --muted-foreground: 240 5% 64.9%;
 
   /* 主题颜色 */
 
@@ -747,16 +752,16 @@ type BuiltinThemeType =
   --secondary-foreground: 0 0% 98%;
 
   /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
-  --accent: 0deg 0% 100% / 8%;
-  --accent-hover: 0deg 0% 100% / 12%;
+  --accent: 216 5% 19%;
+  --accent-hover: 216 5% 24%;
   --accent-foreground: 0 0% 98%;
 
   /* Darker color */
-  --heavy: 0deg 0% 100% / 12%;
+  --heavy: 216 5% 24%;
   --heavy-foreground: var(--accent-foreground);
 
   /* Default border color */
-  --border: 240 3.7% 15.9%;
+  --border: 240 3.7% 22%;
 
   /* Border color for inputs such as <Input />, <Select />, <Textarea /> */
   --input: 0deg 0% 100% / 10%;
@@ -777,15 +782,15 @@ type BuiltinThemeType =
   /* 基本文字大小 */
   --font-size-base: 16px;
 
-  /* 主体内容背景色 */
-  --content: 240 11% 96%;
-
   /* =============component & UI============= */
 
   --sidebar: 222.34deg 10.43% 12.27%;
   --sidebar-deep: 220deg 13.06% 9%;
   --menu: var(--sidebar);
 
+  /* header */
+  --header: 222.34deg 10.43% 12.27%;
+
   color-scheme: dark;
 }
 
@@ -812,6 +817,7 @@ type BuiltinThemeType =
   --ring: 263.4 70% 50.4%;
   --sidebar: 224 71.4% 4.1%;
   --sidebar-deep: 224 71.4% 4.1%;
+  --header: 224 71.4% 4.1%;
 }
 
 .dark[data-theme='pink'],
@@ -837,6 +843,7 @@ type BuiltinThemeType =
   --ring: 346.8 77.2% 49.8%;
   --sidebar: 20 14.3% 4.1%;
   --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
 }
 
 .dark[data-theme='rose'],
@@ -862,6 +869,7 @@ type BuiltinThemeType =
   --ring: 0 72.2% 50.6%;
   --sidebar: 0 0% 3.9%;
   --sidebar-deep: 0 0% 3.9%;
+  --header: 0 0% 3.9%;
 }
 
 .dark[data-theme='sky-blue'],
@@ -887,6 +895,7 @@ type BuiltinThemeType =
   --ring: 224.3 76.3% 48%;
   --sidebar: 222.2 84% 4.9%;
   --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
 }
 
 .dark[data-theme='deep-blue'],
@@ -912,6 +921,7 @@ type BuiltinThemeType =
   --ring: 224.3 76.3% 48%;
   --sidebar: 222.2 84% 4.9%;
   --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
 }
 
 .dark[data-theme='green'],
@@ -937,6 +947,7 @@ type BuiltinThemeType =
   --ring: 142.4 71.8% 29.2%;
   --sidebar: 20 14.3% 4.1%;
   --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
 }
 
 .dark[data-theme='deep-green'],
@@ -962,6 +973,7 @@ type BuiltinThemeType =
   --ring: 142.4 71.8% 29.2%;
   --sidebar: 20 14.3% 4.1%;
   --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
 }
 
 .dark[data-theme='orange'],
@@ -987,6 +999,7 @@ type BuiltinThemeType =
   --ring: 20.5 90.2% 48.2%;
   --sidebar: 20 14.3% 4.1%;
   --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
 }
 
 .dark[data-theme='yellow'],
@@ -1012,6 +1025,7 @@ type BuiltinThemeType =
   --ring: 35.5 91.7% 32.9%;
   --sidebar: 20 14.3% 4.1%;
   --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
 }
 
 .dark[data-theme='zinc'],
@@ -1037,6 +1051,7 @@ type BuiltinThemeType =
   --ring: 240 4.9% 83.9%;
   --sidebar: 240 10% 3.9%;
   --sidebar-deep: 240 10% 3.9%;
+  --header: 240 4.9% 83.9%;
 }
 
 .dark[data-theme='neutral'],
@@ -1062,6 +1077,7 @@ type BuiltinThemeType =
   --ring: 0 0% 83.1%;
   --sidebar: 0 0% 3.9%;
   --sidebar-deep: 0 0% 3.9%;
+  --header: 0 0% 3.9%;
 }
 
 .dark[data-theme='slate'],
@@ -1087,6 +1103,7 @@ type BuiltinThemeType =
   --ring: 212.7 26.8% 83.9;
   --sidebar: 222.2 84% 4.9%;
   --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
 }
 
 .dark[data-theme='gray'],
@@ -1112,6 +1129,7 @@ type BuiltinThemeType =
   --ring: 216 12.2% 83.9%;
   --sidebar: 224 71.4% 4.1%;
   --sidebar-deep: 224 71.4% 4.1%;
+  --header: 224 71.4% 4.1%;
 }
 ```
 
@@ -1200,6 +1218,50 @@ export const overridesPreferences = defineOverridesPreferences({
 });
 ```
 
+## 自定义侧边栏颜色
+
+侧边栏颜色通过`--sidebar`变量来配置
+
+### 默认主题下:
+
+```css
+:root {
+  --sidebar: 0 0% 100%;
+}
+```
+
+### 黑暗模式下
+
+```css
+.dark,
+.dark[data-theme='custom'],
+.dark[data-theme='default'] {
+  --sidebar: 222.34deg 10.43% 12.27%;
+}
+```
+
+## 自定义顶栏颜色
+
+侧边栏颜色通过`--header`变量来配置
+
+### 默认主题下:
+
+```css
+:root {
+  --header: 0 0% 100%;
+}
+```
+
+### 黑暗模式下
+
+```css
+.dark,
+.dark[data-theme='custom'],
+.dark[data-theme='default'] {
+  --header: 222.34deg 10.43% 12.27%;
+}
+```
+
 ## 色弱模式
 
 一般用于特殊场景,将设置为色弱模式,你可以在`preferences.ts`中进行配置:

+ 3 - 0
internal/tailwind-config/src/index.ts

@@ -80,6 +80,9 @@ const customColors = {
     ...createColorsPalette('green'),
     foreground: 'hsl(var(--success-foreground))',
   },
+  header: {
+    DEFAULT: 'hsl(var(--header))',
+  },
   heavy: {
     DEFAULT: 'hsl(var(--heavy))',
     foreground: 'hsl(var(--heavy-foreground))',

+ 16 - 3
packages/@core/base/design/src/design-tokens/dark/index.css

@@ -82,15 +82,15 @@
   /* 基本文字大小 */
   --font-size-base: 16px;
 
-  /* 主体内容背景色 */
-  --content: 240 11% 96%;
-
   /* =============component & UI============= */
 
   --sidebar: 222.34deg 10.43% 12.27%;
   --sidebar-deep: 220deg 13.06% 9%;
   --menu: var(--sidebar);
 
+  /* header */
+  --header: 222.34deg 10.43% 12.27%;
+
   color-scheme: dark;
 }
 
@@ -117,6 +117,7 @@
   --ring: 263.4 70% 50.4%;
   --sidebar: 224 71.4% 4.1%;
   --sidebar-deep: 224 71.4% 4.1%;
+  --header: 224 71.4% 4.1%;
 }
 
 .dark[data-theme='pink'],
@@ -142,6 +143,7 @@
   --ring: 346.8 77.2% 49.8%;
   --sidebar: 20 14.3% 4.1%;
   --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
 }
 
 .dark[data-theme='rose'],
@@ -167,6 +169,7 @@
   --ring: 0 72.2% 50.6%;
   --sidebar: 0 0% 3.9%;
   --sidebar-deep: 0 0% 3.9%;
+  --header: 0 0% 3.9%;
 }
 
 .dark[data-theme='sky-blue'],
@@ -192,6 +195,7 @@
   --ring: 224.3 76.3% 48%;
   --sidebar: 222.2 84% 4.9%;
   --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
 }
 
 .dark[data-theme='deep-blue'],
@@ -217,6 +221,7 @@
   --ring: 224.3 76.3% 48%;
   --sidebar: 222.2 84% 4.9%;
   --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
 }
 
 .dark[data-theme='green'],
@@ -242,6 +247,7 @@
   --ring: 142.4 71.8% 29.2%;
   --sidebar: 20 14.3% 4.1%;
   --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
 }
 
 .dark[data-theme='deep-green'],
@@ -267,6 +273,7 @@
   --ring: 142.4 71.8% 29.2%;
   --sidebar: 20 14.3% 4.1%;
   --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
 }
 
 .dark[data-theme='orange'],
@@ -292,6 +299,7 @@
   --ring: 20.5 90.2% 48.2%;
   --sidebar: 20 14.3% 4.1%;
   --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
 }
 
 .dark[data-theme='yellow'],
@@ -317,6 +325,7 @@
   --ring: 35.5 91.7% 32.9%;
   --sidebar: 20 14.3% 4.1%;
   --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
 }
 
 .dark[data-theme='zinc'],
@@ -342,6 +351,7 @@
   --ring: 240 4.9% 83.9%;
   --sidebar: 240 10% 3.9%;
   --sidebar-deep: 240 10% 3.9%;
+  --header: 240 4.9% 83.9%;
 }
 
 .dark[data-theme='neutral'],
@@ -367,6 +377,7 @@
   --ring: 0 0% 83.1%;
   --sidebar: 0 0% 3.9%;
   --sidebar-deep: 0 0% 3.9%;
+  --header: 0 0% 3.9%;
 }
 
 .dark[data-theme='slate'],
@@ -392,6 +403,7 @@
   --ring: 212.7 26.8% 83.9;
   --sidebar: 222.2 84% 4.9%;
   --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
 }
 
 .dark[data-theme='gray'],
@@ -417,4 +429,5 @@
   --ring: 216 12.2% 83.9%;
   --sidebar: 224 71.4% 4.1%;
   --sidebar-deep: 224 71.4% 4.1%;
+  --header: 224 71.4% 4.1%;
 }

+ 4 - 4
packages/@core/base/design/src/design-tokens/default/index.css

@@ -8,7 +8,7 @@
 
   /* 主体区域背景色 */
   --background-deep: 210 11.11% 96.47%;
-  --foreground: 222 84% 5%;
+  --foreground: 210 6% 21%;
 
   /* Background color for <Card /> */
   --card: 0 0% 100%;
@@ -82,9 +82,6 @@
   /* 基本文字大小 */
   --font-size-base: 16px;
 
-  /* 主体内容背景色 */
-  --content: 240 11% 96%;
-
   /* =============component & UI============= */
 
   /* menu */
@@ -92,6 +89,9 @@
   --sidebar-deep: 0 0% 100%;
   --menu: var(--sidebar);
 
+  /* header */
+  --header: 0 0% 100%;
+
   accent-color: var(--primary);
   color-scheme: light;
 }

+ 1 - 0
packages/@core/preferences/src/config.ts

@@ -90,6 +90,7 @@ const defaultPreferences: Preferences = {
     colorWarning: 'hsl(42 84% 61%)',
     mode: 'dark',
     radius: '0.5',
+    semiDarkHeader: false,
     semiDarkMenu: true,
   },
   transition: {

+ 2 - 0
packages/@core/preferences/src/types.ts

@@ -183,6 +183,8 @@ interface ThemePreferences {
   mode: ThemeModeType;
   /** 圆角 */
   radius: string;
+  /** 是否开启半深色header(只在theme='light'时生效) */
+  semiDarkHeader: boolean;
   /** 是否开启半深色菜单(只在theme='light'时生效) */
   semiDarkMenu: boolean;
 }

+ 6 - 1
packages/@core/ui-kit/layout-ui/src/components/layout-header.vue

@@ -36,6 +36,10 @@ interface Props {
    * 侧边菜单宽度
    */
   sidebarWidth: number;
+  /**
+   * 主题
+   */
+  theme: string | undefined;
   /**
    * 宽度
    */
@@ -76,8 +80,9 @@ function handleToggleMenu() {
 
 <template>
   <header
+    :class="theme"
     :style="style"
-    class="border-border bg-background top-0 flex w-full flex-[0_0_auto] items-center border-b transition-[margin-top] duration-200"
+    class="border-border bg-header top-0 flex w-full flex-[0_0_auto] items-center border-b transition-[margin-top] duration-200"
   >
     <div v-if="slots.logo" :style="logoStyle">
       <slot name="logo"></slot>

+ 4 - 1
packages/@core/ui-kit/layout-ui/src/vben-layout.ts

@@ -72,6 +72,10 @@ interface VbenLayoutProps {
    * @default 'fixed'
    */
   headerMode?: LayoutHeaderModeType;
+  /**
+   * header 顶栏主题
+   */
+  headerTheme?: ThemeModeType;
   /**
    * 是否显示header切换侧边栏按钮
    * @default
@@ -127,7 +131,6 @@ interface VbenLayoutProps {
    * @default 80
    */
   sidebarMixedWidth?: number;
-
   /**
    * 侧边栏
    * @default dark

+ 1 - 0
packages/@core/ui-kit/layout-ui/src/vben-layout.vue

@@ -485,6 +485,7 @@ function handleOpenMenu() {
           :show="!isFullContent && !headerHidden"
           :show-toggle-btn="showHeaderToggleButton"
           :sidebar-width="sidebarWidth"
+          :theme="headerTheme"
           :width="mainStyle.width"
           :z-index="headerZIndex"
           @open-menu="handleOpenMenu"

+ 1 - 1
packages/@core/ui-kit/menu-ui/src/components/menu.vue

@@ -776,7 +776,7 @@ $namespace: vben;
   &.is-active {
     div[data-state='open'] > .#{$namespace}-sub-menu-content,
     > .#{$namespace}-sub-menu-content {
-      font-weight: 500;
+      // font-weight: 500;
       color: var(--menu-submenu-active-color);
       text-decoration: none;
       cursor: pointer;

+ 2 - 2
packages/@core/ui-kit/shadcn-ui/src/components/ui/hover-card/HoverCardContent.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { computed, type HTMLAttributes } from 'vue';
+import { computed } from 'vue';
 
 import { cn } from '@vben-core/shared';
 
@@ -11,7 +11,7 @@ import {
 } from 'radix-vue';
 
 const props = withDefaults(
-  defineProps<{ class?: HTMLAttributes['class'] } & HoverCardContentProps>(),
+  defineProps<{ class?: any } & HoverCardContentProps>(),
   {
     sideOffset: 4,
   },

+ 1 - 1
packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue

@@ -109,7 +109,7 @@ function scrollIntoView() {
                 <!-- divider -->
                 <div
                   v-if="i !== 0 && tab.key !== active"
-                  class="tabs-chrome__divider bg-foreground/80 absolute left-[var(--gap)] top-1/2 z-0 h-4 w-[1px] translate-y-[-50%] transition-all"
+                  class="tabs-chrome__divider bg-foreground/60 absolute left-[var(--gap)] top-1/2 z-0 h-4 w-[1px] translate-y-[-50%] transition-all"
                 ></div>
                 <!-- background -->
                 <div

+ 8 - 6
packages/effects/layouts/src/basic/layout.vue

@@ -47,15 +47,16 @@ const userStore = useUserStore();
 const { updateWatermark } = useWatermark();
 const lockStore = useLockStore();
 
-const headerMenuTheme = computed(() => {
-  return isDark.value ? 'dark' : 'light';
-});
-
 const sidebarTheme = computed(() => {
   const dark = isDark.value || preferences.theme.semiDarkMenu;
   return dark ? 'dark' : 'light';
 });
 
+const headerTheme = computed(() => {
+  const dark = isDark.value || preferences.theme.semiDarkHeader;
+  return dark ? 'dark' : 'light';
+});
+
 const logoClass = computed(() => {
   const { collapsedShowTitle } = preferences.sidebar;
   const classes: string[] = [];
@@ -161,6 +162,7 @@ const headerSlots = computed(() => {
     :footer-fixed="preferences.footer.fixed"
     :header-hidden="preferences.header.hidden"
     :header-mode="preferences.header.mode"
+    :header-theme="headerTheme"
     :header-toggle-sidebar-button="preferences.widget.sidebarToggle"
     :header-visible="preferences.header.enable"
     :is-mobile="preferences.app.isMobile"
@@ -200,7 +202,7 @@ const headerSlots = computed(() => {
         :collapsed="logoCollapsed"
         :src="preferences.logo.source"
         :text="preferences.app.name"
-        :theme="showHeaderNav ? headerMenuTheme : theme"
+        :theme="showHeaderNav ? headerTheme : theme"
       />
     </template>
     <!-- 头部区域 -->
@@ -222,7 +224,7 @@ const headerSlots = computed(() => {
             :default-active="headerActive"
             :menus="wrapperMenus(headerMenus)"
             :rounded="isMenuRounded"
-            :theme="headerMenuTheme"
+            :theme="headerTheme"
             class="w-full"
             mode="horizontal"
             @select="handleMenuSelect"

+ 5 - 3
packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue

@@ -13,9 +13,8 @@ defineOptions({
 });
 
 const modelValue = defineModel<string>({ default: 'auto' });
-const themeSemiDarkMenu = defineModel<boolean>('themeSemiDarkMenu', {
-  default: true,
-});
+const themeSemiDarkMenu = defineModel<boolean>('themeSemiDarkMenu');
+const themeSemiDarkHeader = defineModel<boolean>('themeSemiDarkHeader');
 
 const THEME_PRESET: Array<{ icon: Component; name: ThemeModeType }> = [
   {
@@ -77,5 +76,8 @@ function nameView(name: string) {
     >
       {{ $t('preferences.theme.darkMenu') }}
     </SwitchItem>
+    <SwitchItem v-model="themeSemiDarkHeader" :disabled="modelValue === 'dark'">
+      {{ $t('preferences.theme.darkHeader') }}
+    </SwitchItem>
   </div>
 </template>

+ 2 - 0
packages/effects/layouts/src/widgets/preferences/preferences-sheet.vue

@@ -74,6 +74,7 @@ const themeBuiltinType = defineModel<BuiltinThemeType>('themeBuiltinType');
 const themeMode = defineModel<ThemeModeType>('themeMode');
 const themeRadius = defineModel<string>('themeRadius');
 const themeSemiDarkMenu = defineModel<boolean>('themeSemiDarkMenu');
+const themeSemiDarkHeader = defineModel<boolean>('themeSemiDarkHeader');
 
 const sidebarEnable = defineModel<boolean>('sidebarEnable');
 const sidebarWidth = defineModel<number>('sidebarWidth');
@@ -274,6 +275,7 @@ async function handleReset() {
             <Block :title="$t('preferences.theme.title')">
               <Theme
                 v-model="themeMode"
+                v-model:theme-semi-dark-header="themeSemiDarkHeader"
                 v-model:theme-semi-dark-menu="themeSemiDarkMenu"
               />
             </Block>

+ 1 - 0
packages/locales/src/langs/en-US.json

@@ -237,6 +237,7 @@
       "light": "Light",
       "dark": "Dark",
       "darkMenu": "Semi Dark Menu",
+      "darkHeader": "Semi Dark Header",
       "weakMode": "Weak Mode",
       "grayMode": "Gray Mode",
       "builtin": {

+ 1 - 0
packages/locales/src/langs/zh-CN.json

@@ -237,6 +237,7 @@
       "light": "浅色",
       "dark": "深色",
       "darkMenu": "深色菜单",
+      "darkHeader": "深色顶栏",
       "weakMode": "色弱模式",
       "grayMode": "灰色模式",
       "builtin": {