fix: 双列菜单模式下新增深色侧边栏和深色侧边栏子栏 (#7542)

* fix: 双列菜单模式下新增深色侧边栏和深色侧边栏子栏

* fix: 修复报错 config.test.ts.snap

* fix: 修复lint报错

* fix: 修复侧边栏菜单文本内容溢出问题

* fix: 修复lint报错
This commit is contained in:
zouawen
2026-02-11 16:08:32 +08:00
committed by GitHub
parent 7fe8d7b4be
commit 32379ba4b7
12 changed files with 97 additions and 33 deletions

View File

@@ -120,6 +120,7 @@ exports[`defaultPreferences immutability test > should not modify the config obj
"radius": "0.5", "radius": "0.5",
"semiDarkHeader": false, "semiDarkHeader": false,
"semiDarkSidebar": false, "semiDarkSidebar": false,
"semiDarkSidebarSub": false,
}, },
"transition": { "transition": {
"enable": true, "enable": true,

View File

@@ -121,6 +121,7 @@ const defaultPreferences: Preferences = {
fontSize: 16, fontSize: 16,
semiDarkHeader: false, semiDarkHeader: false,
semiDarkSidebar: false, semiDarkSidebar: false,
semiDarkSidebarSub: false,
}, },
transition: { transition: {
enable: true, enable: true,

View File

@@ -253,6 +253,8 @@ interface ThemePreferences {
semiDarkHeader: boolean; semiDarkHeader: boolean;
/** 是否开启半深色菜单只在theme='light'时生效) */ /** 是否开启半深色菜单只在theme='light'时生效) */
semiDarkSidebar: boolean; semiDarkSidebar: boolean;
/** 是否开启半深色子菜单只在theme='light'时生效) */
semiDarkSidebarSub: boolean;
} }
interface TransitionPreferences { interface TransitionPreferences {

View File

@@ -77,7 +77,10 @@ interface Props {
* 主题 * 主题
*/ */
theme: string; theme: string;
/**
* 子主题
*/
themeSub: string;
/** /**
* 宽度 * 宽度
*/ */
@@ -289,35 +292,38 @@ function handleMouseleave() {
v-if="showCollapseButton && !isSidebarMixed" v-if="showCollapseButton && !isSidebarMixed"
v-model:collapsed="collapse" v-model:collapsed="collapse"
/> />
<div
v-if="isSidebarMixed"
ref="asideRef"
:class="{
'border-l': extraVisible,
}"
:style="extraStyle"
class="fixed top-0 h-full overflow-hidden border-r border-border bg-sidebar transition-all duration-200"
>
<SidebarCollapseButton
v-if="isSidebarMixed && expandOnHover"
v-model:collapsed="extraCollapse"
/>
<SidebarFixedButton
v-if="!extraCollapse"
v-model:expand-on-hover="expandOnHover"
/>
<div v-if="!extraCollapse" :style="extraTitleStyle" class="pl-2">
<slot name="extra-title"></slot>
</div>
<VbenScrollbar
:style="extraContentStyle"
class="border-border py-2"
shadow
shadow-border
>
<slot name="extra"></slot>
</VbenScrollbar>
</div>
</aside> </aside>
<div
v-if="isSidebarMixed"
ref="asideRef"
:class="[
themeSub,
{
'border-l': extraVisible,
},
]"
:style="extraStyle"
class="fixed top-0 h-full overflow-hidden border-r border-border bg-sidebar transition-all duration-200"
>
<SidebarCollapseButton
v-if="isSidebarMixed && expandOnHover"
v-model:collapsed="extraCollapse"
/>
<SidebarFixedButton
v-if="!extraCollapse"
v-model:expand-on-hover="expandOnHover"
/>
<div v-if="!extraCollapse" :style="extraTitleStyle" class="pl-2">
<slot name="extra-title"></slot>
</div>
<VbenScrollbar
:style="extraContentStyle"
class="border-border py-2"
shadow
shadow-border
>
<slot name="extra"></slot>
</VbenScrollbar>
</div>
</template> </template>

View File

@@ -146,6 +146,11 @@ interface VbenLayoutProps {
* @default dark * @default dark
*/ */
sidebarTheme?: ThemeModeType; sidebarTheme?: ThemeModeType;
/**
* 侧边栏子栏
* @default dark
*/
sidebarThemeSub?: ThemeModeType;
/** /**
* 侧边栏宽度 * 侧边栏宽度
* @default 210 * @default 210

View File

@@ -56,6 +56,7 @@ const props = withDefaults(defineProps<Props>(), {
sidebarHidden: false, sidebarHidden: false,
sidebarMixedWidth: 80, sidebarMixedWidth: 80,
sidebarTheme: 'dark', sidebarTheme: 'dark',
sidebarThemeSub: 'dark',
sidebarWidth: 180, sidebarWidth: 180,
sideCollapseWidth: 60, sideCollapseWidth: 60,
tabbarEnable: true, tabbarEnable: true,
@@ -502,6 +503,7 @@ const idMainContent = ELEMENT_ID_MAIN_CONTENT;
:mixed-width="sidebarMixedWidth" :mixed-width="sidebarMixedWidth"
:show="showSidebar" :show="showSidebar"
:theme="sidebarTheme" :theme="sidebarTheme"
:theme-sub="sidebarThemeSub"
:width="getSidebarWidth" :width="getSidebarWidth"
:z-index="sidebarZIndex" :z-index="sidebarZIndex"
@leave="() => emit('sideMouseLeave')" @leave="() => emit('sideMouseLeave')"

View File

@@ -151,10 +151,12 @@ $namespace: vben;
} }
&__name { &__name {
width: 100%;
margin-top: 8px; margin-top: 8px;
margin-bottom: 0; margin-bottom: 0;
font-size: calc(var(--font-size-base, 16px) * 0.75); font-size: calc(var(--font-size-base, 16px) * 0.75);
font-weight: 400; font-weight: 400;
text-align: center;
transition: all 0.25s ease; transition: all 0.25s ease;
} }
} }

View File

@@ -60,6 +60,11 @@ const sidebarTheme = computed(() => {
return dark ? 'dark' : 'light'; return dark ? 'dark' : 'light';
}); });
const sidebarThemeSub = computed(() => {
const dark = isDark.value || preferences.theme.semiDarkSidebarSub;
return dark ? 'dark' : 'light';
});
const headerTheme = computed(() => { const headerTheme = computed(() => {
const dark = isDark.value || preferences.theme.semiDarkHeader; const dark = isDark.value || preferences.theme.semiDarkHeader;
return dark ? 'dark' : 'light'; return dark ? 'dark' : 'light';
@@ -240,6 +245,7 @@ const headerSlots = computed(() => {
:sidebar-hidden="preferences.sidebar.hidden" :sidebar-hidden="preferences.sidebar.hidden"
:sidebar-mixed-width="preferences.sidebar.mixedWidth" :sidebar-mixed-width="preferences.sidebar.mixedWidth"
:sidebar-theme="sidebarTheme" :sidebar-theme="sidebarTheme"
:sidebar-theme-sub="sidebarThemeSub"
:sidebar-width="preferences.sidebar.width" :sidebar-width="preferences.sidebar.width"
:side-collapse-width="preferences.sidebar.collapseWidth" :side-collapse-width="preferences.sidebar.collapseWidth"
:tabbar-enable="preferences.tabbar.enable" :tabbar-enable="preferences.tabbar.enable"
@@ -355,7 +361,7 @@ const headerSlots = computed(() => {
:collapse="preferences.sidebar.extraCollapse" :collapse="preferences.sidebar.extraCollapse"
:menus="wrapperMenus(extraMenus)" :menus="wrapperMenus(extraMenus)"
:rounded="isMenuRounded" :rounded="isMenuRounded"
:theme="sidebarTheme" :theme="sidebarThemeSub"
/> />
</template> </template>
<template #side-extra-title> <template #side-extra-title>

View File

@@ -3,8 +3,11 @@ import type { Component } from 'vue';
import type { ThemeModeType } from '@vben/types'; import type { ThemeModeType } from '@vben/types';
import { watch } from 'vue';
import { MoonStar, Sun, SunMoon } from '@vben/icons'; import { MoonStar, Sun, SunMoon } from '@vben/icons';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
import { usePreferences } from '@vben/preferences';
import SwitchItem from '../switch-item.vue'; import SwitchItem from '../switch-item.vue';
@@ -14,8 +17,20 @@ defineOptions({
const modelValue = defineModel<string>({ default: 'auto' }); const modelValue = defineModel<string>({ default: 'auto' });
const themeSemiDarkSidebar = defineModel<boolean>('themeSemiDarkSidebar'); const themeSemiDarkSidebar = defineModel<boolean>('themeSemiDarkSidebar');
const themeSemiDarkSidebarSub = defineModel<boolean>('themeSemiDarkSidebarSub');
const themeSemiDarkHeader = defineModel<boolean>('themeSemiDarkHeader'); const themeSemiDarkHeader = defineModel<boolean>('themeSemiDarkHeader');
const { layout } = usePreferences();
watch(
() => themeSemiDarkSidebar.value,
() => {
if (!themeSemiDarkSidebar.value) {
themeSemiDarkSidebarSub.value = themeSemiDarkSidebar.value;
}
},
);
const THEME_PRESET: Array<{ icon: Component; name: ThemeModeType }> = [ const THEME_PRESET: Array<{ icon: Component; name: ThemeModeType }> = [
{ {
icon: Sun, icon: Sun,
@@ -71,11 +86,27 @@ function nameView(name: string) {
<SwitchItem <SwitchItem
v-model="themeSemiDarkSidebar" v-model="themeSemiDarkSidebar"
:disabled="modelValue === 'dark'" :disabled="
modelValue === 'dark' ||
layout === 'header-nav' ||
layout === 'full-content'
"
:tip="$t('preferences.theme.darkSidebarTip')"
class="mt-6" class="mt-6"
> >
{{ $t('preferences.theme.darkSidebar') }} {{ $t('preferences.theme.darkSidebar') }}
</SwitchItem> </SwitchItem>
<SwitchItem
v-model="themeSemiDarkSidebarSub"
:disabled="
modelValue === 'dark' ||
(layout !== 'header-mixed-nav' && layout !== 'sidebar-mixed-nav') ||
!themeSemiDarkSidebar
"
:tip="$t('preferences.theme.darkSidebarSubTip')"
>
{{ $t('preferences.theme.darkSidebarSub') }}
</SwitchItem>
<SwitchItem v-model="themeSemiDarkHeader" :disabled="modelValue === 'dark'"> <SwitchItem v-model="themeSemiDarkHeader" :disabled="modelValue === 'dark'">
{{ $t('preferences.theme.darkHeader') }} {{ $t('preferences.theme.darkHeader') }}
</SwitchItem> </SwitchItem>

View File

@@ -88,6 +88,7 @@ const themeMode = defineModel<ThemeModeType>('themeMode');
const themeRadius = defineModel<string>('themeRadius'); const themeRadius = defineModel<string>('themeRadius');
const themeFontSize = defineModel<number>('themeFontSize'); const themeFontSize = defineModel<number>('themeFontSize');
const themeSemiDarkSidebar = defineModel<boolean>('themeSemiDarkSidebar'); const themeSemiDarkSidebar = defineModel<boolean>('themeSemiDarkSidebar');
const themeSemiDarkSidebarSub = defineModel<boolean>('themeSemiDarkSidebarSub');
const themeSemiDarkHeader = defineModel<boolean>('themeSemiDarkHeader'); const themeSemiDarkHeader = defineModel<boolean>('themeSemiDarkHeader');
const sidebarEnable = defineModel<boolean>('sidebarEnable'); const sidebarEnable = defineModel<boolean>('sidebarEnable');
@@ -319,6 +320,7 @@ async function handleReset() {
v-model="themeMode" v-model="themeMode"
v-model:theme-semi-dark-header="themeSemiDarkHeader" v-model:theme-semi-dark-header="themeSemiDarkHeader"
v-model:theme-semi-dark-sidebar="themeSemiDarkSidebar" v-model:theme-semi-dark-sidebar="themeSemiDarkSidebar"
v-model:theme-semi-dark-sidebar-sub="themeSemiDarkSidebarSub"
/> />
</Block> </Block>
<Block :title="$t('preferences.theme.builtin.title')"> <Block :title="$t('preferences.theme.builtin.title')">

View File

@@ -127,6 +127,9 @@
"light": "Light", "light": "Light",
"dark": "Dark", "dark": "Dark",
"darkSidebar": "Semi Dark Sidebar", "darkSidebar": "Semi Dark Sidebar",
"darkSidebarTip": "It can be enabled when the theme is light, and the layout is neither 'Horizontal' nor 'Full Content'.",
"darkSidebarSub": "Semi Dark Sidebar Sub",
"darkSidebarSubTip": "It can be enabled when the theme is light, the semi dark sidebar is enabled, and the layout uses 'Two-Column' menu mode.",
"darkHeader": "Semi Dark Header", "darkHeader": "Semi Dark Header",
"weakMode": "Weak Mode", "weakMode": "Weak Mode",
"grayMode": "Gray Mode", "grayMode": "Gray Mode",

View File

@@ -127,6 +127,9 @@
"light": "浅色", "light": "浅色",
"dark": "深色", "dark": "深色",
"darkSidebar": "深色侧边栏", "darkSidebar": "深色侧边栏",
"darkSidebarTip": "当主题为浅色,布局不为水平菜单或不为内容全屏时可开启",
"darkSidebarSub": "深色侧边栏子栏",
"darkSidebarSubTip": "当主题为浅色,开启深色侧边栏且布局使用双列菜单模式时可开启",
"darkHeader": "深色顶栏", "darkHeader": "深色顶栏",
"weakMode": "色弱模式", "weakMode": "色弱模式",
"grayMode": "灰色模式", "grayMode": "灰色模式",