fix: fix a series of known problems,fixed #54
parent
01e95e029f
commit
276ef2ebc3
|
@ -43,7 +43,7 @@
|
||||||
"@vben/utils": "workspace:*",
|
"@vben/utils": "workspace:*",
|
||||||
"@vueuse/core": "^10.11.0",
|
"@vueuse/core": "^10.11.0",
|
||||||
"ant-design-vue": "^4.2.3",
|
"ant-design-vue": "^4.2.3",
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.12",
|
||||||
"pinia": "2.1.7",
|
"pinia": "2.1.7",
|
||||||
"vue": "^3.4.32",
|
"vue": "^3.4.32",
|
||||||
"vue-router": "^4.4.0"
|
"vue-router": "^4.4.0"
|
||||||
|
|
|
@ -27,6 +27,12 @@
|
||||||
"embedded": "Embedded",
|
"embedded": "Embedded",
|
||||||
"externalLink": "External Link"
|
"externalLink": "External Link"
|
||||||
},
|
},
|
||||||
|
"badge": {
|
||||||
|
"title": "Menu Badge",
|
||||||
|
"dot": "Dot Badge",
|
||||||
|
"text": "Text Badge",
|
||||||
|
"color": "Badge Color"
|
||||||
|
},
|
||||||
"fallback": { "title": "Fallback Page" },
|
"fallback": { "title": "Fallback Page" },
|
||||||
"features": {
|
"features": {
|
||||||
"title": "Features",
|
"title": "Features",
|
||||||
|
|
|
@ -27,6 +27,12 @@
|
||||||
"embedded": "内嵌",
|
"embedded": "内嵌",
|
||||||
"externalLink": "外链"
|
"externalLink": "外链"
|
||||||
},
|
},
|
||||||
|
"badge": {
|
||||||
|
"title": "菜单徽标",
|
||||||
|
"dot": "点徽标",
|
||||||
|
"text": "文本徽标",
|
||||||
|
"color": "徽标颜色"
|
||||||
|
},
|
||||||
"fallback": {
|
"fallback": {
|
||||||
"title": "缺省页"
|
"title": "缺省页"
|
||||||
},
|
},
|
||||||
|
|
|
@ -177,6 +177,48 @@ const routes: RouteRecordRaw[] = [
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
meta: {
|
||||||
|
icon: 'lucide:circle-dot',
|
||||||
|
title: $t('page.demos.badge.title'),
|
||||||
|
},
|
||||||
|
name: 'BadgeDemo',
|
||||||
|
path: 'badge',
|
||||||
|
redirect: '/demos/badge/dot',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
name: 'BadgeDotDemo',
|
||||||
|
component: () => import('#/views/demos/badge/index.vue'),
|
||||||
|
path: 'dot',
|
||||||
|
meta: {
|
||||||
|
badgeType: 'dot',
|
||||||
|
icon: 'lucide:square-dot',
|
||||||
|
title: $t('page.demos.badge.dot'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'BadgeTextDemo',
|
||||||
|
component: () => import('#/views/demos/badge/index.vue'),
|
||||||
|
path: 'text',
|
||||||
|
meta: {
|
||||||
|
badge: 'New',
|
||||||
|
icon: 'lucide:square-dot',
|
||||||
|
title: $t('page.demos.badge.text'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'BadgeColorDemo',
|
||||||
|
component: () => import('#/views/demos/badge/index.vue'),
|
||||||
|
path: 'color',
|
||||||
|
meta: {
|
||||||
|
badge: 'Hot',
|
||||||
|
badgeVariants: 'destructive',
|
||||||
|
icon: 'lucide:square-dot',
|
||||||
|
title: $t('page.demos.badge.color'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'ic:round-settings-input-composite',
|
icon: 'ic:round-settings-input-composite',
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { Fallback } from '@vben/common-ui';
|
||||||
|
|
||||||
|
defineOptions({ name: 'Menu321' });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Fallback description="用于徽标示例" status="coming-soon" title="徽标示例" />
|
||||||
|
</template>
|
|
@ -31,7 +31,7 @@
|
||||||
"@changesets/git": "^3.0.0",
|
"@changesets/git": "^3.0.0",
|
||||||
"@manypkg/get-packages": "^2.2.2",
|
"@manypkg/get-packages": "^2.2.2",
|
||||||
"consola": "^3.2.3",
|
"consola": "^3.2.3",
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.12",
|
||||||
"find-up": "^7.0.0",
|
"find-up": "^7.0.0",
|
||||||
"nanoid": "^5.0.7",
|
"nanoid": "^5.0.7",
|
||||||
"pkg-types": "^1.1.3",
|
"pkg-types": "^1.1.3",
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
"tailwindcss": "^3.4.3"
|
"tailwindcss": "^3.4.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@iconify/json": "^2.2.228",
|
"@iconify/json": "^2.2.229",
|
||||||
"@iconify/tailwind": "^1.1.1",
|
"@iconify/tailwind": "^1.1.1",
|
||||||
"@tailwindcss/forms": "^0.5.7",
|
"@tailwindcss/forms": "^0.5.7",
|
||||||
"@tailwindcss/nesting": "0.0.0-insiders.565cd3e",
|
"@tailwindcss/nesting": "0.0.0-insiders.565cd3e",
|
||||||
|
|
|
@ -32,7 +32,7 @@ const shadcnUiColors = {
|
||||||
},
|
},
|
||||||
background: {
|
background: {
|
||||||
DEFAULT: 'hsl(var(--background))',
|
DEFAULT: 'hsl(var(--background))',
|
||||||
content: 'hsl(var(--background-content))',
|
deep: 'hsl(var(--background-deep))',
|
||||||
},
|
},
|
||||||
border: {
|
border: {
|
||||||
DEFAULT: 'hsl(var(--border))',
|
DEFAULT: 'hsl(var(--border))',
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
"@vben/node-utils": "workspace:*",
|
"@vben/node-utils": "workspace:*",
|
||||||
"@vitejs/plugin-vue": "^5.0.5",
|
"@vitejs/plugin-vue": "^5.0.5",
|
||||||
"@vitejs/plugin-vue-jsx": "^4.0.0",
|
"@vitejs/plugin-vue-jsx": "^4.0.0",
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.12",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"rollup": "^4.18.1",
|
"rollup": "^4.18.1",
|
||||||
"rollup-plugin-visualizer": "^5.12.0",
|
"rollup-plugin-visualizer": "^5.12.0",
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
"@vue/test-utils": "^2.4.6",
|
"@vue/test-utils": "^2.4.6",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"cspell": "^8.11.0",
|
"cspell": "^8.11.0",
|
||||||
"husky": "^9.1.0",
|
"husky": "^9.1.1",
|
||||||
"is-ci": "^3.0.1",
|
"is-ci": "^3.0.1",
|
||||||
"jsdom": "^24.1.0",
|
"jsdom": "^24.1.0",
|
||||||
"rimraf": "^6.0.1",
|
"rimraf": "^6.0.1",
|
||||||
|
|
|
@ -61,7 +61,7 @@ const defaultPreferences: Preferences = {
|
||||||
},
|
},
|
||||||
sidebar: {
|
sidebar: {
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
collapsedShowTitle: true,
|
collapsedShowTitle: false,
|
||||||
enable: true,
|
enable: true,
|
||||||
expandOnHover: true,
|
expandOnHover: true,
|
||||||
extraCollapse: true,
|
extraCollapse: true,
|
||||||
|
|
|
@ -84,6 +84,10 @@ function usePreferences() {
|
||||||
return isMixedNav.value || isSideMixedNav.value || isSideNav.value;
|
return isMixedNav.value || isSideMixedNav.value || isSideNav.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const sidebarCollapsed = computed(() => {
|
||||||
|
return preferences.sidebar.collapsed;
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @zh_CN 是否开启keep-alive
|
* @zh_CN 是否开启keep-alive
|
||||||
* 在tabs可见以及开启keep-alive的情况下才开启
|
* 在tabs可见以及开启keep-alive的情况下才开启
|
||||||
|
@ -172,6 +176,7 @@ function usePreferences() {
|
||||||
isSideNav,
|
isSideNav,
|
||||||
keepAlive,
|
keepAlive,
|
||||||
layout,
|
layout,
|
||||||
|
sidebarCollapsed,
|
||||||
theme,
|
theme,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,14 +23,14 @@
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
text-rendering: optimizelegibility;
|
text-rendering: optimizelegibility;
|
||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
}
|
|
||||||
|
|
||||||
html.invert-mode {
|
&.invert-mode {
|
||||||
@apply invert;
|
@apply invert;
|
||||||
}
|
}
|
||||||
|
|
||||||
html.grayscale-mode {
|
&.grayscale-mode {
|
||||||
@apply grayscale;
|
@apply grayscale;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#app,
|
#app,
|
||||||
|
@ -41,7 +41,8 @@
|
||||||
|
|
||||||
body {
|
body {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
overflow: overlay;
|
|
||||||
|
/* overflow: overlay; */
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
--background: 222.34deg 10.43% 12.27%;
|
--background: 222.34deg 10.43% 12.27%;
|
||||||
|
|
||||||
/* 主体区域背景色 */
|
/* 主体区域背景色 */
|
||||||
--background-content: 220deg 13.06% 9%;
|
--background-deep: 220deg 13.06% 9%;
|
||||||
--foreground: 220 13% 91%;
|
--foreground: 220 13% 91%;
|
||||||
|
|
||||||
/* Background color for <Card /> */
|
/* Background color for <Card /> */
|
||||||
|
@ -95,7 +95,7 @@
|
||||||
.dark[data-theme='violet'],
|
.dark[data-theme='violet'],
|
||||||
[data-theme='violet'] .dark {
|
[data-theme='violet'] .dark {
|
||||||
--background: 224 71.4% 4.1%;
|
--background: 224 71.4% 4.1%;
|
||||||
--background-content: var(--background);
|
--background-deep: var(--background);
|
||||||
--foreground: 210 20% 98%;
|
--foreground: 210 20% 98%;
|
||||||
--card: 224 71.4% 4.1%;
|
--card: 224 71.4% 4.1%;
|
||||||
--card-foreground: 210 20% 98%;
|
--card-foreground: 210 20% 98%;
|
||||||
|
@ -120,7 +120,7 @@
|
||||||
.dark[data-theme='pink'],
|
.dark[data-theme='pink'],
|
||||||
[data-theme='pink'] .dark {
|
[data-theme='pink'] .dark {
|
||||||
--background: 20 14.3% 4.1%;
|
--background: 20 14.3% 4.1%;
|
||||||
--background-content: var(--background);
|
--background-deep: var(--background);
|
||||||
--foreground: 0 0% 95%;
|
--foreground: 0 0% 95%;
|
||||||
--card: 24 9.8% 10%;
|
--card: 24 9.8% 10%;
|
||||||
--card-foreground: 0 0% 95%;
|
--card-foreground: 0 0% 95%;
|
||||||
|
@ -145,7 +145,7 @@
|
||||||
.dark[data-theme='rose'],
|
.dark[data-theme='rose'],
|
||||||
[data-theme='rose'] .dark {
|
[data-theme='rose'] .dark {
|
||||||
--background: 0 0% 3.9%;
|
--background: 0 0% 3.9%;
|
||||||
--background-content: var(--background);
|
--background-deep: var(--background);
|
||||||
--foreground: 0 0% 98%;
|
--foreground: 0 0% 98%;
|
||||||
--card: 0 0% 3.9%;
|
--card: 0 0% 3.9%;
|
||||||
--card-foreground: 0 0% 98%;
|
--card-foreground: 0 0% 98%;
|
||||||
|
@ -170,7 +170,7 @@
|
||||||
.dark[data-theme='sky-blue'],
|
.dark[data-theme='sky-blue'],
|
||||||
[data-theme='sky-blue'] .dark {
|
[data-theme='sky-blue'] .dark {
|
||||||
--background: 222.2 84% 4.9%;
|
--background: 222.2 84% 4.9%;
|
||||||
--background-content: var(--background);
|
--background-deep: var(--background);
|
||||||
--foreground: 210 40% 98%;
|
--foreground: 210 40% 98%;
|
||||||
--card: 222.2 84% 4.9%;
|
--card: 222.2 84% 4.9%;
|
||||||
--card-foreground: 210 40% 98%;
|
--card-foreground: 210 40% 98%;
|
||||||
|
@ -195,7 +195,7 @@
|
||||||
.dark[data-theme='deep-blue'],
|
.dark[data-theme='deep-blue'],
|
||||||
[data-theme='deep-blue'] .dark {
|
[data-theme='deep-blue'] .dark {
|
||||||
--background: 222.2 84% 4.9%;
|
--background: 222.2 84% 4.9%;
|
||||||
--background-content: var(--background);
|
--background-deep: var(--background);
|
||||||
--foreground: 210 40% 98%;
|
--foreground: 210 40% 98%;
|
||||||
--card: 222.2 84% 4.9%;
|
--card: 222.2 84% 4.9%;
|
||||||
--card-foreground: 210 40% 98%;
|
--card-foreground: 210 40% 98%;
|
||||||
|
@ -220,7 +220,7 @@
|
||||||
.dark[data-theme='green'],
|
.dark[data-theme='green'],
|
||||||
[data-theme='green'] .dark {
|
[data-theme='green'] .dark {
|
||||||
--background: 20 14.3% 4.1%;
|
--background: 20 14.3% 4.1%;
|
||||||
--background-content: var(--background);
|
--background-deep: var(--background);
|
||||||
--foreground: 0 0% 95%;
|
--foreground: 0 0% 95%;
|
||||||
--card: 24 9.8% 10%;
|
--card: 24 9.8% 10%;
|
||||||
--card-foreground: 0 0% 95%;
|
--card-foreground: 0 0% 95%;
|
||||||
|
@ -245,7 +245,7 @@
|
||||||
.dark[data-theme='deep-green'],
|
.dark[data-theme='deep-green'],
|
||||||
[data-theme='deep-green'] .dark {
|
[data-theme='deep-green'] .dark {
|
||||||
--background: 20 14.3% 4.1%;
|
--background: 20 14.3% 4.1%;
|
||||||
--background-content: var(--background);
|
--background-deep: var(--background);
|
||||||
--foreground: 0 0% 95%;
|
--foreground: 0 0% 95%;
|
||||||
--card: 24 9.8% 10%;
|
--card: 24 9.8% 10%;
|
||||||
--card-foreground: 0 0% 95%;
|
--card-foreground: 0 0% 95%;
|
||||||
|
@ -270,7 +270,7 @@
|
||||||
.dark[data-theme='orange'],
|
.dark[data-theme='orange'],
|
||||||
[data-theme='orange'] .dark {
|
[data-theme='orange'] .dark {
|
||||||
--background: 20 14.3% 4.1%;
|
--background: 20 14.3% 4.1%;
|
||||||
--background-content: var(--background);
|
--background-deep: var(--background);
|
||||||
--foreground: 60 9.1% 97.8%;
|
--foreground: 60 9.1% 97.8%;
|
||||||
--card: 20 14.3% 4.1%;
|
--card: 20 14.3% 4.1%;
|
||||||
--card-foreground: 60 9.1% 97.8%;
|
--card-foreground: 60 9.1% 97.8%;
|
||||||
|
@ -295,7 +295,7 @@
|
||||||
.dark[data-theme='yellow'],
|
.dark[data-theme='yellow'],
|
||||||
[data-theme='yellow'] .dark {
|
[data-theme='yellow'] .dark {
|
||||||
--background: 20 14.3% 4.1%;
|
--background: 20 14.3% 4.1%;
|
||||||
--background-content: var(--background);
|
--background-deep: var(--background);
|
||||||
--foreground: 60 9.1% 97.8%;
|
--foreground: 60 9.1% 97.8%;
|
||||||
--card: 20 14.3% 4.1%;
|
--card: 20 14.3% 4.1%;
|
||||||
--card-foreground: 60 9.1% 97.8%;
|
--card-foreground: 60 9.1% 97.8%;
|
||||||
|
@ -320,7 +320,7 @@
|
||||||
.dark[data-theme='zinc'],
|
.dark[data-theme='zinc'],
|
||||||
[data-theme='zinc'] .dark {
|
[data-theme='zinc'] .dark {
|
||||||
--background: 240 10% 3.9%;
|
--background: 240 10% 3.9%;
|
||||||
--background-content: var(--background);
|
--background-deep: var(--background);
|
||||||
--foreground: 0 0% 98%;
|
--foreground: 0 0% 98%;
|
||||||
--card: 240 10% 3.9%;
|
--card: 240 10% 3.9%;
|
||||||
--card-foreground: 0 0% 98%;
|
--card-foreground: 0 0% 98%;
|
||||||
|
@ -345,7 +345,7 @@
|
||||||
.dark[data-theme='neutral'],
|
.dark[data-theme='neutral'],
|
||||||
[data-theme='neutral'] .dark {
|
[data-theme='neutral'] .dark {
|
||||||
--background: 0 0% 3.9%;
|
--background: 0 0% 3.9%;
|
||||||
--background-content: var(--background);
|
--background-deep: var(--background);
|
||||||
--foreground: 0 0% 98%;
|
--foreground: 0 0% 98%;
|
||||||
--card: 0 0% 3.9%;
|
--card: 0 0% 3.9%;
|
||||||
--card-foreground: 0 0% 98%;
|
--card-foreground: 0 0% 98%;
|
||||||
|
@ -370,7 +370,7 @@
|
||||||
.dark[data-theme='slate'],
|
.dark[data-theme='slate'],
|
||||||
[data-theme='slate'] .dark {
|
[data-theme='slate'] .dark {
|
||||||
--background: 222.2 84% 4.9%;
|
--background: 222.2 84% 4.9%;
|
||||||
--background-content: var(--background);
|
--background-deep: var(--background);
|
||||||
--foreground: 210 40% 98%;
|
--foreground: 210 40% 98%;
|
||||||
--card: 222.2 84% 4.9%;
|
--card: 222.2 84% 4.9%;
|
||||||
--card-foreground: 210 40% 98%;
|
--card-foreground: 210 40% 98%;
|
||||||
|
@ -395,7 +395,7 @@
|
||||||
.dark[data-theme='gray'],
|
.dark[data-theme='gray'],
|
||||||
[data-theme='gray'] .dark {
|
[data-theme='gray'] .dark {
|
||||||
--background: 224 71.4% 4.1%;
|
--background: 224 71.4% 4.1%;
|
||||||
--background-content: var(--background);
|
--background-deep: var(--background);
|
||||||
--foreground: 210 20% 98%;
|
--foreground: 210 20% 98%;
|
||||||
--card: 224 71.4% 4.1%;
|
--card: 224 71.4% 4.1%;
|
||||||
--card-foreground: 210 20% 98%;
|
--card-foreground: 210 20% 98%;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
--background: 0 0 100%;
|
--background: 0 0 100%;
|
||||||
|
|
||||||
/* 主体区域背景色 */
|
/* 主体区域背景色 */
|
||||||
--background-content: 210 11.11% 96.47%;
|
--background-deep: 210 11.11% 96.47%;
|
||||||
--foreground: 210 6% 21%;
|
--foreground: 210 6% 21%;
|
||||||
|
|
||||||
/* Background color for <Card /> */
|
/* Background color for <Card /> */
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
/* ============= custom ============= */
|
/* ============= custom ============= */
|
||||||
|
|
||||||
/* 遮罩颜色 */
|
/* 遮罩颜色 */
|
||||||
--overlay: 0deg 0% 0% / 40%;
|
--overlay: 0deg 0% 0% / 30%;
|
||||||
|
|
||||||
/* 基本文字大小 */
|
/* 基本文字大小 */
|
||||||
--font-size-base: 16px;
|
--font-size-base: 16px;
|
||||||
|
|
|
@ -9,50 +9,20 @@ import { useContentHeightListener } from '@vben-core/hooks';
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
* 内容区域定宽
|
* 内容区域定宽
|
||||||
* @default 'wide'
|
|
||||||
*/
|
*/
|
||||||
contentCompact?: ContentCompactType;
|
contentCompact: ContentCompactType;
|
||||||
/**
|
/**
|
||||||
* 定宽布局宽度
|
* 定宽布局宽度
|
||||||
* @default 1200
|
|
||||||
*/
|
*/
|
||||||
contentCompactWidth?: number;
|
contentCompactWidth: number;
|
||||||
/**
|
padding: number;
|
||||||
* padding
|
paddingBottom: number;
|
||||||
* @default 16
|
paddingLeft: number;
|
||||||
*/
|
paddingRight: number;
|
||||||
padding?: number;
|
paddingTop: number;
|
||||||
/**
|
|
||||||
* paddingBottom
|
|
||||||
* @default 16
|
|
||||||
*/
|
|
||||||
paddingBottom?: number;
|
|
||||||
/**
|
|
||||||
* paddingLeft
|
|
||||||
* @default 16
|
|
||||||
*/
|
|
||||||
paddingLeft?: number;
|
|
||||||
/**
|
|
||||||
* paddingRight
|
|
||||||
* @default 16
|
|
||||||
*/
|
|
||||||
paddingRight?: number;
|
|
||||||
/**
|
|
||||||
* paddingTop
|
|
||||||
* @default 16
|
|
||||||
*/
|
|
||||||
paddingTop?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {});
|
||||||
contentCompact: 'wide',
|
|
||||||
contentCompactWidth: 1200,
|
|
||||||
padding: 16,
|
|
||||||
paddingBottom: 16,
|
|
||||||
paddingLeft: 16,
|
|
||||||
paddingRight: 16,
|
|
||||||
paddingTop: 16,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { contentElement } = useContentHeightListener();
|
const { contentElement } = useContentHeightListener();
|
||||||
|
|
||||||
|
@ -83,7 +53,7 @@ const style = computed((): CSSProperties => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<main ref="contentElement" :style="style" class="bg-background-content">
|
<main ref="contentElement" :style="style" class="bg-background-deep">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -4,38 +4,21 @@ import { computed } from 'vue';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
* 是否固定在顶部
|
* 是否固定在底部
|
||||||
* @default true
|
|
||||||
*/
|
*/
|
||||||
fixed?: boolean;
|
fixed?: boolean;
|
||||||
/**
|
height: number;
|
||||||
* 高度
|
|
||||||
* @default 32
|
|
||||||
*/
|
|
||||||
height?: number;
|
|
||||||
/**
|
/**
|
||||||
* 是否显示
|
* 是否显示
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
show?: boolean;
|
show?: boolean;
|
||||||
/**
|
width: string;
|
||||||
* 高度
|
zIndex: number;
|
||||||
* @default 100%
|
|
||||||
*/
|
|
||||||
width?: string;
|
|
||||||
/**
|
|
||||||
* zIndex
|
|
||||||
* @default 0
|
|
||||||
*/
|
|
||||||
zIndex?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
fixed: true,
|
|
||||||
height: 32,
|
|
||||||
show: true,
|
show: true,
|
||||||
width: '100%',
|
|
||||||
zIndex: 0,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const style = computed((): CSSProperties => {
|
const style = computed((): CSSProperties => {
|
||||||
|
@ -53,7 +36,7 @@ const style = computed((): CSSProperties => {
|
||||||
<template>
|
<template>
|
||||||
<footer
|
<footer
|
||||||
:style="style"
|
:style="style"
|
||||||
class="bg-background-content bottom-0 w-full transition-all duration-200"
|
class="bg-background-deep bottom-0 w-full transition-all duration-200"
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
@ -8,61 +8,45 @@ import { VbenIconButton } from '@vben-core/shadcn-ui';
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
* 横屏
|
* 横屏
|
||||||
* @default false
|
|
||||||
*/
|
*/
|
||||||
fullWidth?: boolean;
|
fullWidth: boolean;
|
||||||
/**
|
/**
|
||||||
* 高度
|
* 高度
|
||||||
* @default 60
|
|
||||||
*/
|
*/
|
||||||
height?: number;
|
height: number;
|
||||||
/**
|
/**
|
||||||
* 是否混合导航
|
* 是否混合导航
|
||||||
* @default false
|
* @default false
|
||||||
*/
|
*/
|
||||||
isMixedNav?: boolean;
|
isMixedNav: boolean;
|
||||||
/**
|
/**
|
||||||
* 是否移动端
|
* 是否移动端
|
||||||
* @default false
|
|
||||||
*/
|
*/
|
||||||
isMobile?: boolean;
|
isMobile: boolean;
|
||||||
/**
|
/**
|
||||||
* 是否显示
|
* 是否显示
|
||||||
* @default true
|
|
||||||
*/
|
*/
|
||||||
show?: boolean;
|
show: boolean;
|
||||||
/**
|
/**
|
||||||
* 是否显示关闭菜单按钮
|
* 是否显示关闭菜单按钮
|
||||||
* @default true
|
|
||||||
*/
|
*/
|
||||||
showToggleBtn?: boolean;
|
showToggleBtn: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 侧边菜单宽度
|
* 侧边菜单宽度
|
||||||
* @default 0
|
|
||||||
*/
|
*/
|
||||||
sidebarWidth?: number;
|
sidebarWidth: number;
|
||||||
/**
|
/**
|
||||||
* 宽度
|
* 宽度
|
||||||
* @default 100%
|
|
||||||
*/
|
*/
|
||||||
width?: string;
|
width: string;
|
||||||
/**
|
/**
|
||||||
* zIndex
|
* zIndex
|
||||||
* @default 0
|
|
||||||
*/
|
*/
|
||||||
zIndex?: number;
|
zIndex: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {});
|
||||||
height: 60,
|
|
||||||
isMixedNav: false,
|
|
||||||
show: true,
|
|
||||||
showToggleBtn: false,
|
|
||||||
sidebarWidth: 0,
|
|
||||||
width: '100%',
|
|
||||||
zIndex: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits<{ openMenu: []; toggleSidebar: [] }>();
|
const emit = defineEmits<{ openMenu: []; toggleSidebar: [] }>();
|
||||||
|
|
||||||
|
@ -73,7 +57,6 @@ const style = computed((): CSSProperties => {
|
||||||
const right = !show || !fullWidth ? undefined : 0;
|
const right = !show || !fullWidth ? undefined : 0;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// ...(props.isMixedNav ? { left: 0, position: `fixed` } : {}),
|
|
||||||
height: `${height}px`,
|
height: `${height}px`,
|
||||||
marginTop: show ? 0 : `-${height}px`,
|
marginTop: show ? 0 : `-${height}px`,
|
||||||
right,
|
right,
|
||||||
|
@ -87,11 +70,7 @@ const logoStyle = computed((): CSSProperties => {
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleToggleMenu() {
|
function handleToggleMenu() {
|
||||||
if (props.isMobile) {
|
props.isMobile ? emit('openMenu') : emit('toggleSidebar');
|
||||||
emit('openMenu');
|
|
||||||
} else {
|
|
||||||
emit('toggleSidebar');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { SidebarCollapseButton, SidebarFixedButton } from './widgets';
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
* 折叠区域高度
|
* 折叠区域高度
|
||||||
* @default 32
|
* @default 42
|
||||||
*/
|
*/
|
||||||
collapseHeight?: number;
|
collapseHeight?: number;
|
||||||
/**
|
/**
|
||||||
|
@ -41,6 +41,11 @@ interface Props {
|
||||||
* @default false
|
* @default false
|
||||||
*/
|
*/
|
||||||
isSidebarMixed?: boolean;
|
isSidebarMixed?: boolean;
|
||||||
|
/**
|
||||||
|
* 顶部margin
|
||||||
|
* @default 60
|
||||||
|
*/
|
||||||
|
marginTop?: number;
|
||||||
/**
|
/**
|
||||||
* 混合菜单宽度
|
* 混合菜单宽度
|
||||||
* @default 80
|
* @default 80
|
||||||
|
@ -85,8 +90,9 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
extraWidth: 180,
|
extraWidth: 180,
|
||||||
fixedExtra: false,
|
fixedExtra: false,
|
||||||
isSidebarMixed: false,
|
isSidebarMixed: false,
|
||||||
mixedWidth: 80,
|
marginTop: 0,
|
||||||
paddingTop: 60,
|
mixedWidth: 70,
|
||||||
|
paddingTop: 0,
|
||||||
show: true,
|
show: true,
|
||||||
showCollapseButton: true,
|
showCollapseButton: true,
|
||||||
theme: 'dark',
|
theme: 'dark',
|
||||||
|
@ -108,11 +114,13 @@ const asideRef = shallowRef<HTMLDivElement | null>();
|
||||||
const hiddenSideStyle = computed((): CSSProperties => calcMenuWidthStyle(true));
|
const hiddenSideStyle = computed((): CSSProperties => calcMenuWidthStyle(true));
|
||||||
|
|
||||||
const style = computed((): CSSProperties => {
|
const style = computed((): CSSProperties => {
|
||||||
const { isSidebarMixed, paddingTop, zIndex } = props;
|
const { isSidebarMixed, marginTop, paddingTop, zIndex } = props;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'--scroll-shadow': 'var(--sidebar)',
|
'--scroll-shadow': 'var(--sidebar)',
|
||||||
...calcMenuWidthStyle(false),
|
...calcMenuWidthStyle(false),
|
||||||
|
height: `calc(100% - ${marginTop}px)`,
|
||||||
|
marginTop: `${marginTop}px`,
|
||||||
paddingTop: `${paddingTop}px`,
|
paddingTop: `${paddingTop}px`,
|
||||||
zIndex,
|
zIndex,
|
||||||
...(isSidebarMixed && extraVisible.value ? { transition: 'none' } : {}),
|
...(isSidebarMixed && extraVisible.value ? { transition: 'none' } : {}),
|
||||||
|
@ -222,6 +230,7 @@ function handleMouseleave() {
|
||||||
if (expandOnHover.value) {
|
if (expandOnHover.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
expandOnHovering.value = false;
|
expandOnHovering.value = false;
|
||||||
collapse.value = true;
|
collapse.value = true;
|
||||||
extraVisible.value = false;
|
extraVisible.value = false;
|
||||||
|
@ -233,7 +242,7 @@ function handleMouseleave() {
|
||||||
v-if="domVisible"
|
v-if="domVisible"
|
||||||
:class="theme"
|
:class="theme"
|
||||||
:style="hiddenSideStyle"
|
:style="hiddenSideStyle"
|
||||||
class="h-full transition-all duration-200"
|
class="h-full transition-all duration-150"
|
||||||
></div>
|
></div>
|
||||||
<aside
|
<aside
|
||||||
:class="[
|
:class="[
|
||||||
|
@ -244,7 +253,7 @@ function handleMouseleave() {
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
:style="style"
|
:style="style"
|
||||||
class="border-border fixed left-0 top-0 h-full border-r transition-all duration-200"
|
class="border-border fixed left-0 top-0 h-full border-r transition-all duration-150"
|
||||||
@mouseenter="handleMouseenter"
|
@mouseenter="handleMouseenter"
|
||||||
@mouseleave="handleMouseleave"
|
@mouseleave="handleMouseleave"
|
||||||
>
|
>
|
||||||
|
@ -255,7 +264,7 @@ function handleMouseleave() {
|
||||||
<div v-if="slots.logo" :style="headerStyle">
|
<div v-if="slots.logo" :style="headerStyle">
|
||||||
<slot name="logo"></slot>
|
<slot name="logo"></slot>
|
||||||
</div>
|
</div>
|
||||||
<VbenScrollbar :style="contentStyle" shadow>
|
<VbenScrollbar :style="contentStyle" shadow shadow-border>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</VbenScrollbar>
|
</VbenScrollbar>
|
||||||
|
|
||||||
|
@ -267,8 +276,11 @@ function handleMouseleave() {
|
||||||
<div
|
<div
|
||||||
v-if="isSidebarMixed"
|
v-if="isSidebarMixed"
|
||||||
ref="asideRef"
|
ref="asideRef"
|
||||||
|
:class="{
|
||||||
|
'border-r': extraVisible,
|
||||||
|
}"
|
||||||
:style="extraStyle"
|
:style="extraStyle"
|
||||||
class="border-border bg-sidebar fixed top-0 h-full overflow-hidden border-x transition-all duration-200"
|
class="border-border bg-sidebar fixed top-0 h-full overflow-hidden transition-all duration-200"
|
||||||
>
|
>
|
||||||
<SidebarCollapseButton
|
<SidebarCollapseButton
|
||||||
v-if="isSidebarMixed && expandOnHover"
|
v-if="isSidebarMixed && expandOnHover"
|
||||||
|
@ -286,6 +298,7 @@ function handleMouseleave() {
|
||||||
:style="extraContentStyle"
|
:style="extraContentStyle"
|
||||||
class="border-border border-t py-2"
|
class="border-border border-t py-2"
|
||||||
shadow
|
shadow
|
||||||
|
shadow-border
|
||||||
>
|
>
|
||||||
<slot name="extra"></slot>
|
<slot name="extra"></slot>
|
||||||
</VbenScrollbar>
|
</VbenScrollbar>
|
||||||
|
|
|
@ -5,15 +5,11 @@ import { computed } from 'vue';
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
* 高度
|
* 高度
|
||||||
* @default 30
|
|
||||||
*/
|
*/
|
||||||
height?: number;
|
height: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {});
|
||||||
fixed: true,
|
|
||||||
height: 38,
|
|
||||||
});
|
|
||||||
|
|
||||||
const style = computed((): CSSProperties => {
|
const style = computed((): CSSProperties => {
|
||||||
const { height } = props;
|
const { height } = props;
|
||||||
|
|
|
@ -123,6 +123,11 @@ interface VbenLayoutProps {
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
sidebarEnable?: boolean;
|
sidebarEnable?: boolean;
|
||||||
|
/**
|
||||||
|
* 侧边菜单折叠额外宽度
|
||||||
|
* @default 48
|
||||||
|
*/
|
||||||
|
sidebarExtraCollapsedWidth?: number;
|
||||||
/**
|
/**
|
||||||
* 侧边栏是否隐藏
|
* 侧边栏是否隐藏
|
||||||
* @default false
|
* @default false
|
||||||
|
|
|
@ -21,6 +21,7 @@ defineOptions({
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
contentCompact: 'wide',
|
contentCompact: 'wide',
|
||||||
|
contentCompactWidth: 1200,
|
||||||
contentPadding: 0,
|
contentPadding: 0,
|
||||||
contentPaddingBottom: 0,
|
contentPaddingBottom: 0,
|
||||||
contentPaddingLeft: 0,
|
contentPaddingLeft: 0,
|
||||||
|
@ -39,6 +40,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
layout: 'sidebar-nav',
|
layout: 'sidebar-nav',
|
||||||
sideCollapseWidth: 60,
|
sideCollapseWidth: 60,
|
||||||
sidebarCollapseShowTitle: false,
|
sidebarCollapseShowTitle: false,
|
||||||
|
sidebarExtraCollapsedWidth: 60,
|
||||||
sidebarHidden: false,
|
sidebarHidden: false,
|
||||||
sidebarMixedWidth: 80,
|
sidebarMixedWidth: 80,
|
||||||
sidebarSemiDark: true,
|
sidebarSemiDark: true,
|
||||||
|
@ -62,16 +64,16 @@ const {
|
||||||
isScrolling,
|
isScrolling,
|
||||||
y: scrollY,
|
y: scrollY,
|
||||||
} = useScroll(document);
|
} = useScroll(document);
|
||||||
|
|
||||||
const { y: mouseY } = useMouse({ type: 'client' });
|
const { y: mouseY } = useMouse({ type: 'client' });
|
||||||
|
|
||||||
// side是否处于hover状态展开菜单中
|
// side是否处于hover状态展开菜单中
|
||||||
const sidebarExpandOnHovering = ref(false);
|
const sidebarExpandOnHovering = ref(false);
|
||||||
// const sideHidden = ref(false);
|
|
||||||
const headerIsHidden = ref(false);
|
const headerIsHidden = ref(false);
|
||||||
|
|
||||||
const realLayout = computed(() => {
|
const realLayout = computed(() =>
|
||||||
return props.isMobile ? 'sidebar-nav' : props.layout;
|
props.isMobile ? 'sidebar-nav' : props.layout,
|
||||||
});
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否全屏显示content,不需要侧边、底部、顶部、tab区域
|
* 是否全屏显示content,不需要侧边、底部、顶部、tab区域
|
||||||
|
@ -98,7 +100,7 @@ const isMixedNav = computed(() => realLayout.value === 'mixed-nav');
|
||||||
/**
|
/**
|
||||||
* 顶栏是否自动隐藏
|
* 顶栏是否自动隐藏
|
||||||
*/
|
*/
|
||||||
const isHeaderAuto = computed(() => props.headerMode === 'auto');
|
const isHeaderAutoMode = computed(() => props.headerMode === 'auto');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* header区域高度
|
* header区域高度
|
||||||
|
@ -146,7 +148,7 @@ const sidebarEnableState = computed(() => {
|
||||||
/**
|
/**
|
||||||
* 侧边区域离顶部高度
|
* 侧边区域离顶部高度
|
||||||
*/
|
*/
|
||||||
const sidePaddingTop = computed(() => {
|
const sidebarMarginTop = computed(() => {
|
||||||
const { isMobile } = props;
|
const { isMobile } = props;
|
||||||
return isMixedNav.value && !isMobile ? getHeaderHeight.value : 0;
|
return isMixedNav.value && !isMobile ? getHeaderHeight.value : 0;
|
||||||
});
|
});
|
||||||
|
@ -182,10 +184,10 @@ const getSidebarWidth = computed(() => {
|
||||||
/**
|
/**
|
||||||
* 获取扩展区域宽度
|
* 获取扩展区域宽度
|
||||||
*/
|
*/
|
||||||
const getExtraWidth = computed(() => {
|
const sidebarExtraWidth = computed(() => {
|
||||||
const { sidebarWidth } = props;
|
const { sidebarExtraCollapsedWidth, sidebarWidth } = props;
|
||||||
|
|
||||||
return sidebarExtraCollapse.value ? getSideCollapseWidth.value : sidebarWidth;
|
return sidebarExtraCollapse.value ? sidebarExtraCollapsedWidth : sidebarWidth;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -269,19 +271,29 @@ const mainStyle = computed(() => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 计算 tabbar 的样式
|
||||||
const tabbarStyle = computed((): CSSProperties => {
|
const tabbarStyle = computed((): CSSProperties => {
|
||||||
let width = '';
|
let width = '';
|
||||||
let marginLeft = 0;
|
let marginLeft = 0;
|
||||||
|
|
||||||
|
// 如果不是混合导航,tabbar 的宽度为 100%
|
||||||
if (!isMixedNav.value) {
|
if (!isMixedNav.value) {
|
||||||
width = '100%';
|
width = '100%';
|
||||||
} else if (sidebarEnable.value) {
|
} else if (sidebarEnable.value) {
|
||||||
|
// 鼠标在侧边栏上时,且侧边栏展开时的宽度
|
||||||
|
const onHoveringWidth = sidebarExpandOnHover.value
|
||||||
|
? props.sidebarWidth
|
||||||
|
: getSideCollapseWidth.value;
|
||||||
|
|
||||||
|
// 设置 marginLeft,根据侧边栏是否折叠来决定
|
||||||
marginLeft = sidebarCollapse.value
|
marginLeft = sidebarCollapse.value
|
||||||
? getSideCollapseWidth.value
|
? getSideCollapseWidth.value
|
||||||
: props.sidebarWidth;
|
: onHoveringWidth;
|
||||||
|
|
||||||
width = `calc(100% - ${getSidebarWidth.value}px)`;
|
// 设置 tabbar 的宽度,计算方式为 100% 减去侧边栏的宽度
|
||||||
|
width = `calc(100% - ${sidebarCollapse.value ? getSidebarWidth.value : onHoveringWidth}px)`;
|
||||||
} else {
|
} else {
|
||||||
|
// 默认情况下,tabbar 的宽度为 100%
|
||||||
width = '100%';
|
width = '100%';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,7 +312,7 @@ const contentStyle = computed((): CSSProperties => {
|
||||||
fixed &&
|
fixed &&
|
||||||
!fullContent.value &&
|
!fullContent.value &&
|
||||||
!headerIsHidden.value &&
|
!headerIsHidden.value &&
|
||||||
(!isHeaderAuto.value || scrollY.value < headerWrapperHeight.value)
|
(!isHeaderAutoMode.value || scrollY.value < headerWrapperHeight.value)
|
||||||
? `${headerWrapperHeight.value}px`
|
? `${headerWrapperHeight.value}px`
|
||||||
: 0,
|
: 0,
|
||||||
paddingBottom: `${footerEnable && footerFixed ? footerHeight : 0}px`,
|
paddingBottom: `${footerEnable && footerFixed ? footerHeight : 0}px`,
|
||||||
|
@ -333,7 +345,12 @@ const headerWrapperStyle = computed((): CSSProperties => {
|
||||||
*/
|
*/
|
||||||
const sidebarZIndex = computed(() => {
|
const sidebarZIndex = computed(() => {
|
||||||
const { isMobile, zIndex } = props;
|
const { isMobile, zIndex } = props;
|
||||||
const offset = isMobile || isSideMode.value ? 1 : -1;
|
let offset = isMobile || isSideMode.value ? 1 : -1;
|
||||||
|
|
||||||
|
if (isMixedNav.value) {
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
|
||||||
return zIndex + offset;
|
return zIndex + offset;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -366,7 +383,12 @@ const showHeaderLogo = computed(() => {
|
||||||
watch(
|
watch(
|
||||||
() => props.isMobile,
|
() => props.isMobile,
|
||||||
(val) => {
|
(val) => {
|
||||||
sidebarCollapse.value = val;
|
if (val) {
|
||||||
|
sidebarCollapse.value = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -379,7 +401,7 @@ watch(
|
||||||
watch(
|
watch(
|
||||||
[() => props.headerMode, () => mouseY.value],
|
[() => props.headerMode, () => mouseY.value],
|
||||||
() => {
|
() => {
|
||||||
if (!isHeaderAuto.value || isMixedNav.value || fullContent.value) {
|
if (!isHeaderAutoMode.value || isMixedNav.value || fullContent.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
headerIsHidden.value = true;
|
headerIsHidden.value = true;
|
||||||
|
@ -434,10 +456,6 @@ function handleClickMask() {
|
||||||
sidebarCollapse.value = true;
|
sidebarCollapse.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleToggleSidebar() {
|
|
||||||
emit('toggleSidebar');
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleOpenMenu() {
|
function handleOpenMenu() {
|
||||||
sidebarCollapse.value = false;
|
sidebarCollapse.value = false;
|
||||||
}
|
}
|
||||||
|
@ -456,12 +474,12 @@ function handleOpenMenu() {
|
||||||
v-model:extra-visible="sidebarExtraVisible"
|
v-model:extra-visible="sidebarExtraVisible"
|
||||||
:collapse-width="getSideCollapseWidth"
|
:collapse-width="getSideCollapseWidth"
|
||||||
:dom-visible="!isMobile"
|
:dom-visible="!isMobile"
|
||||||
:extra-width="getExtraWidth"
|
:extra-width="sidebarExtraWidth"
|
||||||
:fixed-extra="sidebarExpandOnHover"
|
:fixed-extra="sidebarExpandOnHover"
|
||||||
:header-height="isMixedNav ? 0 : getHeaderHeight"
|
:header-height="isMixedNav ? 0 : getHeaderHeight"
|
||||||
:is-sidebar-mixed="isSidebarMixedNav"
|
:is-sidebar-mixed="isSidebarMixedNav"
|
||||||
|
:margin-top="sidebarMarginTop"
|
||||||
:mixed-width="sidebarMixedWidth"
|
:mixed-width="sidebarMixedWidth"
|
||||||
:padding-top="sidePaddingTop"
|
|
||||||
:show="showSidebar"
|
:show="showSidebar"
|
||||||
:theme="sidebarFace.theme"
|
:theme="sidebarFace.theme"
|
||||||
:width="getSidebarWidth"
|
:width="getSidebarWidth"
|
||||||
|
@ -506,7 +524,7 @@ function handleOpenMenu() {
|
||||||
:width="mainStyle.width"
|
:width="mainStyle.width"
|
||||||
:z-index="headerZIndex"
|
:z-index="headerZIndex"
|
||||||
@open-menu="handleOpenMenu"
|
@open-menu="handleOpenMenu"
|
||||||
@toggle-sidebar="handleToggleSidebar"
|
@toggle-sidebar="() => emit('toggleSidebar')"
|
||||||
>
|
>
|
||||||
<template v-if="showHeaderLogo" #logo>
|
<template v-if="showHeaderLogo" #logo>
|
||||||
<slot name="logo"></slot>
|
<slot name="logo"></slot>
|
||||||
|
|
|
@ -397,7 +397,7 @@ $namespace: vben;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
.#{$namespace}-menu__icon {
|
.#{$namespace}-menu__icon {
|
||||||
transform: scale(1.3);
|
transform: scale(1.2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,7 +422,7 @@ $namespace: vben;
|
||||||
.#{$namespace}-menu__popup-container,
|
.#{$namespace}-menu__popup-container,
|
||||||
.#{$namespace}-menu {
|
.#{$namespace}-menu {
|
||||||
--menu-title-width: 140px;
|
--menu-title-width: 140px;
|
||||||
--menu-item-icon-width: 20px;
|
--menu-item-icon-size: 16px;
|
||||||
--menu-item-height: 38px;
|
--menu-item-height: 38px;
|
||||||
--menu-item-padding-y: 22px;
|
--menu-item-padding-y: 22px;
|
||||||
--menu-item-padding-x: 12px;
|
--menu-item-padding-x: 12px;
|
||||||
|
@ -430,7 +430,7 @@ $namespace: vben;
|
||||||
--menu-item-popup-padding-x: 12px;
|
--menu-item-popup-padding-x: 12px;
|
||||||
--menu-item-margin-y: 3px;
|
--menu-item-margin-y: 3px;
|
||||||
--menu-item-margin-x: 0px;
|
--menu-item-margin-x: 0px;
|
||||||
--menu-item-collapse-padding-y: 25px;
|
--menu-item-collapse-padding-y: 23.5px;
|
||||||
--menu-item-collapse-padding-x: 0px;
|
--menu-item-collapse-padding-x: 0px;
|
||||||
--menu-item-collapse-margin-y: 4px;
|
--menu-item-collapse-margin-y: 4px;
|
||||||
--menu-item-collapse-margin-x: 0px;
|
--menu-item-collapse-margin-x: 0px;
|
||||||
|
@ -701,10 +701,9 @@ $namespace: vben;
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
// width: var(--menu-item-icon-width);
|
width: var(--menu-item-icon-size);
|
||||||
max-height: var(--menu-item-icon-width);
|
height: var(--menu-item-icon-size);
|
||||||
margin-right: 12px;
|
margin-right: 8px;
|
||||||
font-size: 20px;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
@ -810,7 +809,7 @@ $namespace: vben;
|
||||||
width: inherit;
|
width: inherit;
|
||||||
margin-top: -8px;
|
margin-top: -8px;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
font-size: 16px;
|
// font-size: 16px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: transform 0.25s ease;
|
transition: transform 0.25s ease;
|
||||||
|
|
|
@ -25,14 +25,6 @@ const emit = defineEmits<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { b, e, is } = useNamespace('normal-menu');
|
const { b, e, is } = useNamespace('normal-menu');
|
||||||
|
|
||||||
function handleClick(menu: MenuRecordRaw) {
|
|
||||||
emit('select', menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMouseenter(menu: MenuRecordRaw) {
|
|
||||||
emit('enter', menu);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -49,8 +41,8 @@ function handleMouseenter(menu: MenuRecordRaw) {
|
||||||
<template v-for="menu in menus" :key="menu.path">
|
<template v-for="menu in menus" :key="menu.path">
|
||||||
<li
|
<li
|
||||||
:class="[e('item'), is('active', activePath === menu.path)]"
|
:class="[e('item'), is('active', activePath === menu.path)]"
|
||||||
@click="handleClick(menu)"
|
@click="() => emit('select', menu)"
|
||||||
@mouseenter="handleMouseenter(menu)"
|
@mouseenter="() => emit('enter', menu)"
|
||||||
>
|
>
|
||||||
<VbenIcon :class="e('icon')" :icon="menu.icon" fallback />
|
<VbenIcon :class="e('icon')" :icon="menu.icon" fallback />
|
||||||
<span :class="e('name')" class="truncate"> {{ menu.name }}</span>
|
<span :class="e('name')" class="truncate"> {{ menu.name }}</span>
|
||||||
|
@ -64,10 +56,9 @@ $namespace: vben;
|
||||||
.#{$namespace}-normal-menu {
|
.#{$namespace}-normal-menu {
|
||||||
--menu-item-margin-y: 4px;
|
--menu-item-margin-y: 4px;
|
||||||
--menu-item-margin-x: 0px;
|
--menu-item-margin-x: 0px;
|
||||||
--menu-item-padding-y: 8px;
|
--menu-item-padding-y: 9px;
|
||||||
--menu-item-padding-x: 0px;
|
--menu-item-padding-x: 0px;
|
||||||
--menu-item-radius: 0px;
|
--menu-item-radius: 0px;
|
||||||
--menu-dark-background: 0deg 0% 100% / 10%;
|
|
||||||
|
|
||||||
height: calc(100% - 4px);
|
height: calc(100% - 4px);
|
||||||
|
|
||||||
|
@ -82,12 +73,9 @@ $namespace: vben;
|
||||||
|
|
||||||
&:not(.is-active):hover {
|
&:not(.is-active):hover {
|
||||||
color: hsl(var(--primary-foreground));
|
color: hsl(var(--primary-foreground));
|
||||||
background-color: hsl(var(--menu-dark-background));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-active {
|
&.is-active {
|
||||||
background-color: hsl(var(--menu-dark-background));
|
|
||||||
|
|
||||||
.#{$namespace}-normal-menu__name,
|
.#{$namespace}-normal-menu__name,
|
||||||
.#{$namespace}-normal-menu__icon {
|
.#{$namespace}-normal-menu__icon {
|
||||||
color: hsl(var(--primary-foreground));
|
color: hsl(var(--primary-foreground));
|
||||||
|
@ -129,7 +117,7 @@ $namespace: vben;
|
||||||
border-color 0.15s ease;
|
border-color 0.15s ease;
|
||||||
|
|
||||||
&.is-active {
|
&.is-active {
|
||||||
@apply text-primary bg-primary/20;
|
@apply text-primary bg-primary/15 dark:bg-accent;
|
||||||
|
|
||||||
.#{$namespace}-normal-menu__name,
|
.#{$namespace}-normal-menu__name,
|
||||||
.#{$namespace}-normal-menu__icon {
|
.#{$namespace}-normal-menu__icon {
|
||||||
|
@ -138,14 +126,12 @@ $namespace: vben;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.is-active):hover {
|
&:not(.is-active):hover {
|
||||||
@apply text-foreground;
|
@apply dark:bg-accent text-primary bg-heavy dark:text-foreground;
|
||||||
|
|
||||||
background-color: hsl(var(--menu-dark-background));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
.#{$namespace}-normal-menu__icon {
|
.#{$namespace}-normal-menu__icon {
|
||||||
transform: scale(1.3);
|
transform: scale(1.2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ function handleClick(path?: string) {
|
||||||
<VbenIcon
|
<VbenIcon
|
||||||
v-if="item.icon && showIcon"
|
v-if="item.icon && showIcon"
|
||||||
:icon="item.icon"
|
:icon="item.icon"
|
||||||
class="mr-1 size-5 flex-shrink-0"
|
class="mr-1 size-4 flex-shrink-0"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
:class="{
|
:class="{
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
|
||||||
* Logo 图标 alt
|
|
||||||
*/
|
|
||||||
alt?: string;
|
|
||||||
/**
|
/**
|
||||||
* 是否收起文本
|
* 是否收起文本
|
||||||
*/
|
*/
|
||||||
collapse?: boolean;
|
collapsed?: boolean;
|
||||||
/**
|
/**
|
||||||
* Logo 跳转地址
|
* Logo 跳转地址
|
||||||
*/
|
*/
|
||||||
|
@ -25,7 +19,7 @@ interface Props {
|
||||||
/**
|
/**
|
||||||
* Logo 文本
|
* Logo 文本
|
||||||
*/
|
*/
|
||||||
text?: string;
|
text: string;
|
||||||
/**
|
/**
|
||||||
* Logo 主题
|
* Logo 主题
|
||||||
*/
|
*/
|
||||||
|
@ -33,39 +27,34 @@ interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Logo',
|
name: 'VbenLogo',
|
||||||
});
|
});
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
withDefaults(defineProps<Props>(), {
|
||||||
alt: 'Vben',
|
collapsed: false,
|
||||||
collapse: false,
|
|
||||||
href: 'javascript:void 0',
|
href: 'javascript:void 0',
|
||||||
logoSize: 36,
|
logoSize: 32,
|
||||||
src: '',
|
src: '',
|
||||||
text: '',
|
|
||||||
theme: 'light',
|
theme: 'light',
|
||||||
});
|
});
|
||||||
const logoClass = computed(() => {
|
|
||||||
return [props.theme, props.collapse ? 'collapsed' : ''];
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="logoClass" class="flex h-full items-center text-lg">
|
<div :class="theme" class="flex h-full items-center text-lg">
|
||||||
<a
|
<a
|
||||||
:class="$attrs.class"
|
:class="$attrs.class"
|
||||||
:href="href"
|
:href="href"
|
||||||
class="flex h-full items-center gap-2 overflow-hidden px-3 font-semibold leading-normal transition-all duration-500"
|
class="flex h-full items-center gap-2 overflow-hidden px-3 text-lg font-semibold leading-normal transition-all duration-500"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
v-if="src"
|
v-if="src"
|
||||||
:alt="alt"
|
:alt="text"
|
||||||
:src="src"
|
:src="src"
|
||||||
:width="logoSize"
|
:width="logoSize"
|
||||||
class="relative rounded-none bg-transparent"
|
class="relative rounded-none bg-transparent"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
v-if="!collapse"
|
v-if="!collapsed"
|
||||||
class="text-primary dark:text-foreground truncate text-nowrap"
|
class="text-primary dark:text-foreground truncate text-nowrap"
|
||||||
>
|
>
|
||||||
{{ text }}
|
{{ text }}
|
||||||
|
|
|
@ -49,7 +49,7 @@ const badgeStyle = computed(() => {
|
||||||
v-else
|
v-else
|
||||||
:class="badgeClass"
|
:class="badgeClass"
|
||||||
:style="badgeStyle"
|
:style="badgeStyle"
|
||||||
class="rounded-md px-1.5 py-0.5 text-xs"
|
class="text-primary-foreground rounded-xl px-1.5 py-0.5 text-xs"
|
||||||
>
|
>
|
||||||
{{ badge }}
|
{{ badge }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,12 +12,14 @@ interface Props {
|
||||||
class?: HTMLAttributes['class'];
|
class?: HTMLAttributes['class'];
|
||||||
horizontal?: boolean;
|
horizontal?: boolean;
|
||||||
shadow?: boolean;
|
shadow?: boolean;
|
||||||
|
shadowBorder?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
class: '',
|
class: '',
|
||||||
horizontal: false,
|
horizontal: false,
|
||||||
shadow: false,
|
shadow: false,
|
||||||
|
shadowBorder: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const isAtTop = ref(true);
|
const isAtTop = ref(true);
|
||||||
|
@ -42,7 +44,8 @@ function handleScroll(event: Event) {
|
||||||
<div
|
<div
|
||||||
v-if="shadow"
|
v-if="shadow"
|
||||||
:class="{
|
:class="{
|
||||||
'border-border border-t opacity-100': !isAtTop,
|
'opacity-100': !isAtTop,
|
||||||
|
'border-border border-t': shadowBorder && !isAtTop,
|
||||||
}"
|
}"
|
||||||
class="scrollbar-top-shadow pointer-events-none absolute top-0 z-10 h-12 w-full opacity-0 transition-opacity duration-300 ease-in-out will-change-[opacity]"
|
class="scrollbar-top-shadow pointer-events-none absolute top-0 z-10 h-12 w-full opacity-0 transition-opacity duration-300 ease-in-out will-change-[opacity]"
|
||||||
></div>
|
></div>
|
||||||
|
@ -50,7 +53,8 @@ function handleScroll(event: Event) {
|
||||||
<div
|
<div
|
||||||
v-if="shadow"
|
v-if="shadow"
|
||||||
:class="{
|
:class="{
|
||||||
'border-border border-b opacity-100': !isAtTop && !isAtBottom,
|
'opacity-100': !isAtTop && !isAtBottom,
|
||||||
|
'border-border border-t': shadowBorder && !isAtTop && !isAtBottom,
|
||||||
}"
|
}"
|
||||||
class="scrollbar-bottom-shadow pointer-events-none absolute bottom-0 z-10 h-12 w-full opacity-0 transition-opacity duration-300 ease-in-out will-change-[opacity]"
|
class="scrollbar-bottom-shadow pointer-events-none absolute bottom-0 z-10 h-12 w-full opacity-0 transition-opacity duration-300 ease-in-out will-change-[opacity]"
|
||||||
></div>
|
></div>
|
||||||
|
|
|
@ -58,14 +58,6 @@ watch(active, () => {
|
||||||
scrollIntoView();
|
scrollIntoView();
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleClose(key: string) {
|
|
||||||
emit('close', key);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleUnpinTab(tab: TabConfig) {
|
|
||||||
emit('unpin', tab);
|
|
||||||
}
|
|
||||||
|
|
||||||
function scrollIntoView() {
|
function scrollIntoView() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const element = document.querySelector(`.tabs-chrome__item.is-active`);
|
const element = document.querySelector(`.tabs-chrome__item.is-active`);
|
||||||
|
@ -142,21 +134,18 @@ function scrollIntoView() {
|
||||||
<div
|
<div
|
||||||
class="tabs-chrome__extra absolute right-[calc(var(--gap)*1.5)] top-1/2 z-[3] size-4 translate-y-[-50%]"
|
class="tabs-chrome__extra absolute right-[calc(var(--gap)*1.5)] top-1/2 z-[3] size-4 translate-y-[-50%]"
|
||||||
>
|
>
|
||||||
<!-- <div
|
|
||||||
class="tabs-chrome__extra absolute right-[calc(var(--gap)*2)] top-1/2 z-[3] size-4 translate-y-[-50%] opacity-0 transition-opacity group-hover:opacity-100"
|
|
||||||
> -->
|
|
||||||
<!-- close-icon -->
|
<!-- close-icon -->
|
||||||
<X
|
<X
|
||||||
v-show="
|
v-show="
|
||||||
!tab.affixTab && tabsView.length > 1 && tab.closable
|
!tab.affixTab && tabsView.length > 1 && tab.closable
|
||||||
"
|
"
|
||||||
class="hover:bg-accent stroke-accent-foreground/80 hover:stroke-accent-foreground dark:group-[.is-active]:text-accent-foreground group-[.is-active]:text-primary mt-[2px] size-3 cursor-pointer rounded-full transition-all"
|
class="hover:bg-accent stroke-accent-foreground/80 hover:stroke-accent-foreground dark:group-[.is-active]:text-accent-foreground group-[.is-active]:text-primary mt-[2px] size-3 cursor-pointer rounded-full transition-all"
|
||||||
@click.stop="handleClose(tab.key)"
|
@click.stop="() => emit('close', tab.key)"
|
||||||
/>
|
/>
|
||||||
<MdiPin
|
<MdiPin
|
||||||
v-show="tab.affixTab && tabsView.length > 1 && tab.closable"
|
v-show="tab.affixTab && tabsView.length > 1 && tab.closable"
|
||||||
class="hover:bg-accent hover:stroke-accent-foreground group-[.is-active]:text-primary dark:group-[.is-active]:text-accent-foreground mt-[2px] size-3.5 cursor-pointer rounded-full transition-all"
|
class="hover:bg-accent hover:stroke-accent-foreground group-[.is-active]:text-primary dark:group-[.is-active]:text-accent-foreground mt-[2px] size-3.5 cursor-pointer rounded-full transition-all"
|
||||||
@click.stop="handleUnpinTab(tab)"
|
@click.stop="() => emit('unpin', tab)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -59,14 +59,6 @@ watch(active, () => {
|
||||||
scrollIntoView();
|
scrollIntoView();
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleClose(key: string) {
|
|
||||||
emit('close', key);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleUnpinTab(tab: TabConfig) {
|
|
||||||
emit('unpin', tab);
|
|
||||||
}
|
|
||||||
|
|
||||||
function scrollIntoView() {
|
function scrollIntoView() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const element = document.querySelector(`.tabs-chrome__item.is-active`);
|
const element = document.querySelector(`.tabs-chrome__item.is-active`);
|
||||||
|
@ -120,12 +112,12 @@ function scrollIntoView() {
|
||||||
!tab.affixTab && tabsView.length > 1 && tab.closable
|
!tab.affixTab && tabsView.length > 1 && tab.closable
|
||||||
"
|
"
|
||||||
class="hover:bg-accent stroke-accent-foreground/80 hover:stroke-accent-foreground dark:group-[.is-active]:text-accent-foreground group-[.is-active]:text-primary size-3 cursor-pointer rounded-full transition-all"
|
class="hover:bg-accent stroke-accent-foreground/80 hover:stroke-accent-foreground dark:group-[.is-active]:text-accent-foreground group-[.is-active]:text-primary size-3 cursor-pointer rounded-full transition-all"
|
||||||
@click.stop="handleClose(tab.key)"
|
@click.stop="() => emit('close', tab.key)"
|
||||||
/>
|
/>
|
||||||
<MdiPin
|
<MdiPin
|
||||||
v-show="tab.affixTab && tabsView.length > 1 && tab.closable"
|
v-show="tab.affixTab && tabsView.length > 1 && tab.closable"
|
||||||
class="hover:bg-accent hover:stroke-accent-foreground group-[.is-active]:text-primary dark:group-[.is-active]:text-accent-foreground mt-[2px] size-3.5 cursor-pointer rounded-full transition-all"
|
class="hover:bg-accent hover:stroke-accent-foreground group-[.is-active]:text-primary dark:group-[.is-active]:text-accent-foreground mt-[2px] size-3.5 cursor-pointer rounded-full transition-all"
|
||||||
@click.stop="handleUnpinTab(tab)"
|
@click.stop="() => emit('unpin', tab)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ defineOptions({
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="flex-col-center bg-background-content relative px-6 py-10 lg:flex-initial lg:px-8"
|
class="flex-col-center bg-background-deep relative px-6 py-10 lg:flex-initial lg:px-8"
|
||||||
>
|
>
|
||||||
<!-- Toolbar Slot -->
|
<!-- Toolbar Slot -->
|
||||||
<slot name="toolbar">
|
<slot name="toolbar">
|
||||||
|
|
|
@ -30,8 +30,15 @@ defineOptions({ name: 'BasicLayout' });
|
||||||
|
|
||||||
const emit = defineEmits<{ clearPreferencesAndLogout: [] }>();
|
const emit = defineEmits<{ clearPreferencesAndLogout: [] }>();
|
||||||
|
|
||||||
const { isDark, isHeaderNav, isMixedNav, isMobile, isSideMixedNav, layout } =
|
const {
|
||||||
usePreferences();
|
isDark,
|
||||||
|
isHeaderNav,
|
||||||
|
isMixedNav,
|
||||||
|
isMobile,
|
||||||
|
isSideMixedNav,
|
||||||
|
layout,
|
||||||
|
sidebarCollapsed,
|
||||||
|
} = usePreferences();
|
||||||
|
|
||||||
const headerMenuTheme = computed(() => {
|
const headerMenuTheme = computed(() => {
|
||||||
return isDark.value ? 'dark' : 'light';
|
return isDark.value ? 'dark' : 'light';
|
||||||
|
@ -43,38 +50,45 @@ const theme = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const logoClass = computed(() => {
|
const logoClass = computed(() => {
|
||||||
let cls = '';
|
const { collapsedShowTitle } = preferences.sidebar;
|
||||||
const { collapsed, collapsedShowTitle } = preferences.sidebar;
|
const classes: string[] = [];
|
||||||
if (collapsedShowTitle && collapsed && !isMixedNav.value) {
|
|
||||||
cls += ' mx-auto';
|
if (collapsedShowTitle && sidebarCollapsed.value && !isMixedNav.value) {
|
||||||
|
classes.push('mx-auto');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSideMixedNav.value) {
|
if (isSideMixedNav.value) {
|
||||||
cls += ' flex-center';
|
classes.push('flex-center');
|
||||||
}
|
}
|
||||||
return cls;
|
|
||||||
|
return classes.join(' ');
|
||||||
});
|
});
|
||||||
|
|
||||||
const isMenuRounded = computed(() => {
|
const isMenuRounded = computed(() => {
|
||||||
return preferences.navigation.styleType === 'rounded';
|
return preferences.navigation.styleType === 'rounded';
|
||||||
});
|
});
|
||||||
|
|
||||||
const logoCollapse = computed(() => {
|
const logoCollapsed = computed(() => {
|
||||||
if (isHeaderNav.value || isMixedNav.value) {
|
const shouldCollapse = isHeaderNav.value || isMixedNav.value;
|
||||||
|
|
||||||
|
if (shouldCollapse) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { collapsed } = preferences.sidebar;
|
const shouldExpandOnMobile = !sidebarCollapsed.value && isMobile.value;
|
||||||
|
|
||||||
if (!collapsed && isMobile) {
|
if (shouldExpandOnMobile) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return collapsed || isSideMixedNav.value;
|
|
||||||
|
return sidebarCollapsed.value || isSideMixedNav.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
const showHeaderNav = computed(() => {
|
const showHeaderNav = computed(() => {
|
||||||
return isHeaderNav.value || isMixedNav.value;
|
return isHeaderNav.value || isMixedNav.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 侧边多列菜单
|
||||||
const {
|
const {
|
||||||
extraActiveMenu,
|
extraActiveMenu,
|
||||||
extraMenus,
|
extraMenus,
|
||||||
|
@ -89,9 +103,9 @@ const {
|
||||||
handleMenuSelect,
|
handleMenuSelect,
|
||||||
headerActive,
|
headerActive,
|
||||||
headerMenus,
|
headerMenus,
|
||||||
sideActive,
|
sidebarActive,
|
||||||
sideMenus,
|
sidebarMenus,
|
||||||
sideVisible,
|
sidebarVisible,
|
||||||
} = useMixedMenu();
|
} = useMixedMenu();
|
||||||
|
|
||||||
function wrapperMenus(menus: MenuRecordRaw[]) {
|
function wrapperMenus(menus: MenuRecordRaw[]) {
|
||||||
|
@ -127,7 +141,7 @@ function clearPreferencesAndLogout() {
|
||||||
:layout="layout"
|
:layout="layout"
|
||||||
:sidebar-collapse="preferences.sidebar.collapsed"
|
:sidebar-collapse="preferences.sidebar.collapsed"
|
||||||
:sidebar-collapse-show-title="preferences.sidebar.collapsedShowTitle"
|
:sidebar-collapse-show-title="preferences.sidebar.collapsedShowTitle"
|
||||||
:sidebar-enable="sideVisible"
|
:sidebar-enable="sidebarVisible"
|
||||||
:sidebar-expand-on-hover="preferences.sidebar.expandOnHover"
|
:sidebar-expand-on-hover="preferences.sidebar.expandOnHover"
|
||||||
:sidebar-extra-collapse="preferences.sidebar.extraCollapse"
|
:sidebar-extra-collapse="preferences.sidebar.extraCollapse"
|
||||||
:sidebar-hidden="preferences.sidebar.hidden"
|
:sidebar-hidden="preferences.sidebar.hidden"
|
||||||
|
@ -168,9 +182,9 @@ function clearPreferencesAndLogout() {
|
||||||
<!-- logo -->
|
<!-- logo -->
|
||||||
<template #logo>
|
<template #logo>
|
||||||
<VbenLogo
|
<VbenLogo
|
||||||
:alt="preferences.app.name"
|
v-if="preferences.logo.enable"
|
||||||
:class="logoClass"
|
:class="logoClass"
|
||||||
:collapse="logoCollapse"
|
:collapsed="logoCollapsed"
|
||||||
:src="preferences.logo.source"
|
:src="preferences.logo.source"
|
||||||
:text="preferences.app.name"
|
:text="preferences.app.name"
|
||||||
:theme="showHeaderNav ? headerMenuTheme : theme"
|
:theme="showHeaderNav ? headerMenuTheme : theme"
|
||||||
|
@ -215,8 +229,8 @@ function clearPreferencesAndLogout() {
|
||||||
:accordion="preferences.navigation.accordion"
|
:accordion="preferences.navigation.accordion"
|
||||||
:collapse="preferences.sidebar.collapsed"
|
:collapse="preferences.sidebar.collapsed"
|
||||||
:collapse-show-title="preferences.sidebar.collapsedShowTitle"
|
:collapse-show-title="preferences.sidebar.collapsedShowTitle"
|
||||||
:default-active="sideActive"
|
:default-active="sidebarActive"
|
||||||
:menus="wrapperMenus(sideMenus)"
|
:menus="wrapperMenus(sidebarMenus)"
|
||||||
:rounded="isMenuRounded"
|
:rounded="isMenuRounded"
|
||||||
:theme="theme"
|
:theme="theme"
|
||||||
mode="vertical"
|
mode="vertical"
|
||||||
|
@ -224,9 +238,9 @@ function clearPreferencesAndLogout() {
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #mixed-menu>
|
<template #mixed-menu>
|
||||||
|
<!-- :collapse="!preferences.sidebar.collapsedShowTitle" -->
|
||||||
<LayoutMixedMenu
|
<LayoutMixedMenu
|
||||||
:active-path="extraActiveMenu"
|
:active-path="extraActiveMenu"
|
||||||
:collapse="!preferences.sidebar.collapsedShowTitle"
|
|
||||||
:menus="wrapperMenus(headerMenus)"
|
:menus="wrapperMenus(headerMenus)"
|
||||||
:rounded="isMenuRounded"
|
:rounded="isMenuRounded"
|
||||||
:theme="theme"
|
:theme="theme"
|
||||||
|
@ -248,7 +262,6 @@ function clearPreferencesAndLogout() {
|
||||||
<template #side-extra-title>
|
<template #side-extra-title>
|
||||||
<VbenLogo
|
<VbenLogo
|
||||||
v-if="preferences.logo.enable"
|
v-if="preferences.logo.enable"
|
||||||
:alt="preferences.app.name"
|
|
||||||
:text="preferences.app.name"
|
:text="preferences.app.name"
|
||||||
:theme="theme"
|
:theme="theme"
|
||||||
/>
|
/>
|
||||||
|
@ -266,6 +279,7 @@ function clearPreferencesAndLogout() {
|
||||||
<template #content>
|
<template #content>
|
||||||
<LayoutContent />
|
<LayoutContent />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 页脚 -->
|
<!-- 页脚 -->
|
||||||
<template v-if="preferences.footer.enable" #footer>
|
<template v-if="preferences.footer.enable" #footer>
|
||||||
<LayoutFooter>
|
<LayoutFooter>
|
||||||
|
|
|
@ -20,10 +20,6 @@ const emit = defineEmits<{
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
function handleSelect(menu: MenuRecordRaw) {
|
|
||||||
emit('select', menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
const menu = findMenuByPath(props.menus || [], route.path);
|
const menu = findMenuByPath(props.menus || [], route.path);
|
||||||
if (menu) {
|
if (menu) {
|
||||||
|
@ -43,6 +39,6 @@ onBeforeMount(() => {
|
||||||
:rounded="rounded"
|
:rounded="rounded"
|
||||||
:theme="theme"
|
:theme="theme"
|
||||||
@enter="(menu) => emit('enter', menu)"
|
@enter="(menu) => emit('enter', menu)"
|
||||||
@select="handleSelect"
|
@select="(menu) => emit('select', menu)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { MenuRecordRaw } from '@vben-core/typings';
|
import type { MenuRecordRaw } from '@vben-core/typings';
|
||||||
|
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import { findRootMenuByPath } from '@vben-core/helpers';
|
import { findRootMenuByPath } from '@vben-core/helpers';
|
||||||
|
@ -78,6 +78,18 @@ function useExtraMenu() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.path,
|
||||||
|
() => {
|
||||||
|
const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath(
|
||||||
|
menus.value,
|
||||||
|
route.path,
|
||||||
|
);
|
||||||
|
extraActiveMenu.value = rootMenuPath ?? findMenu?.path ?? '';
|
||||||
|
extraMenus.value = rootMenu?.children ?? [];
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
extraActiveMenu,
|
extraActiveMenu,
|
||||||
extraMenus,
|
extraMenus,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { MenuRecordRaw } from '@vben-core/typings';
|
import type { MenuRecordRaw } from '@vben-core/typings';
|
||||||
|
|
||||||
import { computed, onBeforeMount, ref } from 'vue';
|
import { computed, onBeforeMount, ref, watch } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import { findRootMenuByPath } from '@vben-core/helpers';
|
import { findRootMenuByPath } from '@vben-core/helpers';
|
||||||
|
@ -10,8 +10,8 @@ import { useCoreAccessStore } from '@vben-core/stores';
|
||||||
import { useNavigation } from './use-navigation';
|
import { useNavigation } from './use-navigation';
|
||||||
|
|
||||||
function useMixedMenu() {
|
function useMixedMenu() {
|
||||||
const accessStore = useCoreAccessStore();
|
|
||||||
const { navigation } = useNavigation();
|
const { navigation } = useNavigation();
|
||||||
|
const accessStore = useCoreAccessStore();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const splitSideMenus = ref<MenuRecordRaw[]>([]);
|
const splitSideMenus = ref<MenuRecordRaw[]>([]);
|
||||||
const rootMenuPath = ref<string>('');
|
const rootMenuPath = ref<string>('');
|
||||||
|
@ -22,7 +22,7 @@ function useMixedMenu() {
|
||||||
() => preferences.navigation.split && isMixedNav.value,
|
() => preferences.navigation.split && isMixedNav.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
const sideVisible = computed(() => {
|
const sidebarVisible = computed(() => {
|
||||||
const enableSidebar = preferences.sidebar.enable;
|
const enableSidebar = preferences.sidebar.enable;
|
||||||
if (needSplit.value) {
|
if (needSplit.value) {
|
||||||
return enableSidebar && splitSideMenus.value.length > 0;
|
return enableSidebar && splitSideMenus.value.length > 0;
|
||||||
|
@ -49,14 +49,14 @@ function useMixedMenu() {
|
||||||
/**
|
/**
|
||||||
* 侧边菜单
|
* 侧边菜单
|
||||||
*/
|
*/
|
||||||
const sideMenus = computed(() => {
|
const sidebarMenus = computed(() => {
|
||||||
return needSplit.value ? splitSideMenus.value : menus.value;
|
return needSplit.value ? splitSideMenus.value : menus.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 侧边菜单激活路径
|
* 侧边菜单激活路径
|
||||||
*/
|
*/
|
||||||
const sideActive = computed(() => {
|
const sidebarActive = computed(() => {
|
||||||
return route.path;
|
return route.path;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -102,6 +102,13 @@ function useMixedMenu() {
|
||||||
splitSideMenus.value = rootMenu?.children ?? [];
|
splitSideMenus.value = rootMenu?.children ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.path,
|
||||||
|
(path: string) => {
|
||||||
|
calcSideMenus(path);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// 初始化计算侧边菜单
|
// 初始化计算侧边菜单
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
calcSideMenus();
|
calcSideMenus();
|
||||||
|
@ -111,9 +118,9 @@ function useMixedMenu() {
|
||||||
handleMenuSelect,
|
handleMenuSelect,
|
||||||
headerActive,
|
headerActive,
|
||||||
headerMenus,
|
headerMenus,
|
||||||
sideActive,
|
sidebarActive,
|
||||||
sideMenus,
|
sidebarMenus,
|
||||||
sideVisible,
|
sidebarVisible,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,8 +67,8 @@ importers:
|
||||||
specifier: ^8.11.0
|
specifier: ^8.11.0
|
||||||
version: 8.11.0
|
version: 8.11.0
|
||||||
husky:
|
husky:
|
||||||
specifier: ^9.1.0
|
specifier: ^9.1.1
|
||||||
version: 9.1.0
|
version: 9.1.1
|
||||||
is-ci:
|
is-ci:
|
||||||
specifier: ^3.0.1
|
specifier: ^3.0.1
|
||||||
version: 3.0.1
|
version: 3.0.1
|
||||||
|
@ -236,8 +236,8 @@ importers:
|
||||||
specifier: ^4.2.3
|
specifier: ^4.2.3
|
||||||
version: 4.2.3(vue@3.4.32(typescript@5.5.3))
|
version: 4.2.3(vue@3.4.32(typescript@5.5.3))
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.11
|
specifier: ^1.11.12
|
||||||
version: 1.11.11
|
version: 1.11.12
|
||||||
pinia:
|
pinia:
|
||||||
specifier: 2.1.7
|
specifier: 2.1.7
|
||||||
version: 2.1.7(typescript@5.5.3)(vue@3.4.32(typescript@5.5.3))
|
version: 2.1.7(typescript@5.5.3)(vue@3.4.32(typescript@5.5.3))
|
||||||
|
@ -418,8 +418,8 @@ importers:
|
||||||
specifier: ^3.2.3
|
specifier: ^3.2.3
|
||||||
version: 3.2.3
|
version: 3.2.3
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.11
|
specifier: ^1.11.12
|
||||||
version: 1.11.11
|
version: 1.11.12
|
||||||
find-up:
|
find-up:
|
||||||
specifier: ^7.0.0
|
specifier: ^7.0.0
|
||||||
version: 7.0.0
|
version: 7.0.0
|
||||||
|
@ -442,8 +442,8 @@ importers:
|
||||||
internal/tailwind-config:
|
internal/tailwind-config:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@iconify/json':
|
'@iconify/json':
|
||||||
specifier: ^2.2.228
|
specifier: ^2.2.229
|
||||||
version: 2.2.228
|
version: 2.2.229
|
||||||
'@iconify/tailwind':
|
'@iconify/tailwind':
|
||||||
specifier: ^1.1.1
|
specifier: ^1.1.1
|
||||||
version: 1.1.1
|
version: 1.1.1
|
||||||
|
@ -537,8 +537,8 @@ importers:
|
||||||
specifier: ^4.0.0
|
specifier: ^4.0.0
|
||||||
version: 4.0.0(vite@5.3.4(@types/node@20.14.11)(sass@1.77.8)(terser@5.31.3))(vue@3.4.32(typescript@5.5.3))
|
version: 4.0.0(vite@5.3.4(@types/node@20.14.11)(sass@1.77.8)(terser@5.31.3))(vue@3.4.32(typescript@5.5.3))
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.11
|
specifier: ^1.11.12
|
||||||
version: 1.11.11
|
version: 1.11.12
|
||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^16.4.5
|
specifier: ^16.4.5
|
||||||
version: 16.4.5
|
version: 16.4.5
|
||||||
|
@ -2944,8 +2944,8 @@ packages:
|
||||||
resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
|
resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
|
||||||
deprecated: Use @eslint/object-schema instead
|
deprecated: Use @eslint/object-schema instead
|
||||||
|
|
||||||
'@iconify/json@2.2.228':
|
'@iconify/json@2.2.229':
|
||||||
resolution: {integrity: sha512-Xd1CgQ1bCFLrp4t+J2TU+AXM+kVHAFLfhK9FcZD54aMPlzENdQMJ5JhfFzCgnsLBAIW1PbSY2Edbm4tt2Tw9Lg==}
|
resolution: {integrity: sha512-DD1k97sjm87n+C15Ey1dVX1cBKCawfms6N0d+1vvAon5P3yurpPEO9OyU88f53+9Chpo+CuIp3+TihvsghlfQQ==}
|
||||||
|
|
||||||
'@iconify/tailwind@1.1.1':
|
'@iconify/tailwind@1.1.1':
|
||||||
resolution: {integrity: sha512-4mmA//qjZigv7D4KlqcVSYTqfRIJzyts2/lSCAJfCL0rVMIE76+ifJnaE5jxCo1+nYGBF8FsFo0qFOs+sX4EnA==}
|
resolution: {integrity: sha512-4mmA//qjZigv7D4KlqcVSYTqfRIJzyts2/lSCAJfCL0rVMIE76+ifJnaE5jxCo1+nYGBF8FsFo0qFOs+sX4EnA==}
|
||||||
|
@ -4794,8 +4794,8 @@ packages:
|
||||||
dataloader@1.4.0:
|
dataloader@1.4.0:
|
||||||
resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==}
|
resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==}
|
||||||
|
|
||||||
dayjs@1.11.11:
|
dayjs@1.11.12:
|
||||||
resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==}
|
resolution: {integrity: sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==}
|
||||||
|
|
||||||
de-indent@1.0.2:
|
de-indent@1.0.2:
|
||||||
resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
|
resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
|
||||||
|
@ -5847,8 +5847,8 @@ packages:
|
||||||
humanize-ms@1.2.1:
|
humanize-ms@1.2.1:
|
||||||
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
|
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
|
||||||
|
|
||||||
husky@9.1.0:
|
husky@9.1.1:
|
||||||
resolution: {integrity: sha512-8XCjbomYTGdNF2h50dio3T3zghmZ9f/ZNzr99YwSkvDdhEjJGs5qzy8tbFx+SG8yCx2wn9nMVfZxVrr/yT8gNQ==}
|
resolution: {integrity: sha512-fCqlqLXcBnXa/TJXmT93/A36tJsjdJkibQ1MuIiFyCCYUlpYpIaj2mv1w+3KR6Rzu1IC3slFTje5f6DUp2A2rg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
@ -11402,7 +11402,7 @@ snapshots:
|
||||||
|
|
||||||
'@humanwhocodes/object-schema@2.0.3': {}
|
'@humanwhocodes/object-schema@2.0.3': {}
|
||||||
|
|
||||||
'@iconify/json@2.2.228':
|
'@iconify/json@2.2.229':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@iconify/types': 2.0.0
|
'@iconify/types': 2.0.0
|
||||||
pathe: 1.1.2
|
pathe: 1.1.2
|
||||||
|
@ -12772,7 +12772,7 @@ snapshots:
|
||||||
array-tree-filter: 2.1.0
|
array-tree-filter: 2.1.0
|
||||||
async-validator: 4.2.5
|
async-validator: 4.2.5
|
||||||
csstype: 3.1.3
|
csstype: 3.1.3
|
||||||
dayjs: 1.11.11
|
dayjs: 1.11.12
|
||||||
dom-align: 1.12.4
|
dom-align: 1.12.4
|
||||||
dom-scroll-into-view: 2.0.1
|
dom-scroll-into-view: 2.0.1
|
||||||
lodash: 4.17.21
|
lodash: 4.17.21
|
||||||
|
@ -13652,7 +13652,7 @@ snapshots:
|
||||||
|
|
||||||
dataloader@1.4.0: {}
|
dataloader@1.4.0: {}
|
||||||
|
|
||||||
dayjs@1.11.11: {}
|
dayjs@1.11.12: {}
|
||||||
|
|
||||||
de-indent@1.0.2: {}
|
de-indent@1.0.2: {}
|
||||||
|
|
||||||
|
@ -14948,7 +14948,7 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
|
|
||||||
husky@9.1.0: {}
|
husky@9.1.1: {}
|
||||||
|
|
||||||
iconv-lite@0.4.24:
|
iconv-lite@0.4.24:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
Loading…
Reference in New Issue