mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-25 16:16:20 +08:00
feat: support custom background colors for sidebar and header (#4151)
* feat: support custom background colors for sidebar and header * fix: type error
This commit is contained in:
@@ -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%;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -90,6 +90,7 @@ const defaultPreferences: Preferences = {
|
||||
colorWarning: 'hsl(42 84% 61%)',
|
||||
mode: 'dark',
|
||||
radius: '0.5',
|
||||
semiDarkHeader: false,
|
||||
semiDarkMenu: true,
|
||||
},
|
||||
transition: {
|
||||
|
@@ -183,6 +183,8 @@ interface ThemePreferences {
|
||||
mode: ThemeModeType;
|
||||
/** 圆角 */
|
||||
radius: string;
|
||||
/** 是否开启半深色header(只在theme='light'时生效) */
|
||||
semiDarkHeader: boolean;
|
||||
/** 是否开启半深色菜单(只在theme='light'时生效) */
|
||||
semiDarkMenu: boolean;
|
||||
}
|
||||
|
@@ -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>
|
||||
|
@@ -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
|
||||
|
@@ -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"
|
||||
|
@@ -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;
|
||||
|
@@ -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,
|
||||
},
|
||||
|
@@ -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
|
||||
|
@@ -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"
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -237,6 +237,7 @@
|
||||
"light": "Light",
|
||||
"dark": "Dark",
|
||||
"darkMenu": "Semi Dark Menu",
|
||||
"darkHeader": "Semi Dark Header",
|
||||
"weakMode": "Weak Mode",
|
||||
"grayMode": "Gray Mode",
|
||||
"builtin": {
|
||||
|
@@ -237,6 +237,7 @@
|
||||
"light": "浅色",
|
||||
"dark": "深色",
|
||||
"darkMenu": "深色菜单",
|
||||
"darkHeader": "深色顶栏",
|
||||
"weakMode": "色弱模式",
|
||||
"grayMode": "灰色模式",
|
||||
"builtin": {
|
||||
|
Reference in New Issue
Block a user