feat(project): add menu split config
parent
d1cdea430e
commit
a0423eb9ba
|
@ -7,7 +7,7 @@ type LayoutType =
|
||||||
|
|
||||||
type BreadcrumbStyle = 'background' | 'normal';
|
type BreadcrumbStyle = 'background' | 'normal';
|
||||||
|
|
||||||
type NavigationStyle = 'normal' | 'rounded';
|
type NavigationStyle = 'plain' | 'rounded';
|
||||||
|
|
||||||
type ThemeType = 'auto' | 'dark' | 'light';
|
type ThemeType = 'auto' | 'dark' | 'light';
|
||||||
|
|
||||||
|
@ -77,6 +77,8 @@ interface Preference {
|
||||||
logo: string;
|
logo: string;
|
||||||
/** logo是否可见 */
|
/** logo是否可见 */
|
||||||
logoVisible: boolean;
|
logoVisible: boolean;
|
||||||
|
/** 导航菜单是否切割,只在 layout=mixed-nav 生效 */
|
||||||
|
navigationSplit: boolean;
|
||||||
/** 导航菜单风格 */
|
/** 导航菜单风格 */
|
||||||
navigationStyle: NavigationStyle;
|
navigationStyle: NavigationStyle;
|
||||||
/** 是否开启页面加载进度条 */
|
/** 是否开启页面加载进度条 */
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import type { SelectListItem } from '@vben/types';
|
|
||||||
|
|
||||||
import { $t } from '@vben/locales';
|
|
||||||
|
|
||||||
import ToggleItem from '../toggle-item.vue';
|
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: 'PreferenceNavigationConfig',
|
|
||||||
});
|
|
||||||
|
|
||||||
defineProps<{ disabled: boolean }>();
|
|
||||||
|
|
||||||
const navigationStyle = defineModel<string>('navigationStyle');
|
|
||||||
|
|
||||||
const stylesItems: SelectListItem[] = [
|
|
||||||
{ label: $t('preference.normal'), value: 'normal' },
|
|
||||||
{ label: $t('preference.rounded'), value: 'rounded' },
|
|
||||||
];
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<ToggleItem v-model="navigationStyle" :items="stylesItems" disabled>
|
|
||||||
{{ $t('preference.navigation-style') }}
|
|
||||||
</ToggleItem>
|
|
||||||
</template>
|
|
|
@ -1,12 +1,12 @@
|
||||||
export { default as Block } from './block.vue';
|
export { default as Block } from './block.vue';
|
||||||
export { default as Animation } from './general/animation.vue';
|
export { default as Animation } from './general/animation.vue';
|
||||||
export { default as General } from './general/general.vue';
|
export { default as General } from './general/general.vue';
|
||||||
export { default as Navigation } from './general/navigation.vue';
|
|
||||||
export { default as Breadcrumb } from './layout/breadcrumb.vue';
|
export { default as Breadcrumb } from './layout/breadcrumb.vue';
|
||||||
export { default as Content } from './layout/content.vue';
|
export { default as Content } from './layout/content.vue';
|
||||||
export { default as Footer } from './layout/footer.vue';
|
export { default as Footer } from './layout/footer.vue';
|
||||||
export { default as Header } from './layout/header.vue';
|
export { default as Header } from './layout/header.vue';
|
||||||
export { default as Layout } from './layout/layout.vue';
|
export { default as Layout } from './layout/layout.vue';
|
||||||
|
export { default as Navigation } from './layout/navigation.vue';
|
||||||
export { default as Sidebar } from './layout/sidebar.vue';
|
export { default as Sidebar } from './layout/sidebar.vue';
|
||||||
export { default as Tabs } from './layout/tabs.vue';
|
export { default as Tabs } from './layout/tabs.vue';
|
||||||
export { default as SwitchItem } from './switch-item.vue';
|
export { default as SwitchItem } from './switch-item.vue';
|
||||||
|
|
|
@ -28,19 +28,28 @@ const typeItems: SelectListItem[] = [
|
||||||
<SwitchItem v-model="breadcrumbVisible" :disabled="disabled">
|
<SwitchItem v-model="breadcrumbVisible" :disabled="disabled">
|
||||||
{{ $t('preference.breadcrumb-enable') }}
|
{{ $t('preference.breadcrumb-enable') }}
|
||||||
</SwitchItem>
|
</SwitchItem>
|
||||||
<SwitchItem v-model="breadcrumbHideOnlyOne" :disabled="!breadcrumbVisible">
|
<SwitchItem
|
||||||
|
v-model="breadcrumbHideOnlyOne"
|
||||||
|
:disabled="!breadcrumbVisible || disabled"
|
||||||
|
>
|
||||||
{{ $t('preference.breadcrumb-hide-only-one') }}
|
{{ $t('preference.breadcrumb-hide-only-one') }}
|
||||||
</SwitchItem>
|
</SwitchItem>
|
||||||
<SwitchItem v-model="breadcrumbHome" :disabled="!breadcrumbVisible">
|
<SwitchItem
|
||||||
|
v-model="breadcrumbHome"
|
||||||
|
:disabled="!breadcrumbVisible || disabled"
|
||||||
|
>
|
||||||
{{ $t('preference.breadcrumb-home') }}
|
{{ $t('preference.breadcrumb-home') }}
|
||||||
</SwitchItem>
|
</SwitchItem>
|
||||||
<SwitchItem v-model="breadcrumbIcon" :disabled="!breadcrumbVisible">
|
<SwitchItem
|
||||||
|
v-model="breadcrumbIcon"
|
||||||
|
:disabled="!breadcrumbVisible || disabled"
|
||||||
|
>
|
||||||
{{ $t('preference.breadcrumb-icon') }}
|
{{ $t('preference.breadcrumb-icon') }}
|
||||||
</SwitchItem>
|
</SwitchItem>
|
||||||
<ToggleItem
|
<ToggleItem
|
||||||
v-model="breadcrumbStyle"
|
v-model="breadcrumbStyle"
|
||||||
:items="typeItems"
|
:items="typeItems"
|
||||||
:disabled="!breadcrumbVisible"
|
:disabled="!breadcrumbVisible || disabled"
|
||||||
>
|
>
|
||||||
{{ $t('preference.breadcrumb-style') }}
|
{{ $t('preference.breadcrumb-style') }}
|
||||||
</ToggleItem>
|
</ToggleItem>
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { SelectListItem } from '@vben/types';
|
||||||
|
|
||||||
|
import { $t } from '@vben/locales';
|
||||||
|
|
||||||
|
import SwitchItem from '../switch-item.vue';
|
||||||
|
import ToggleItem from '../toggle-item.vue';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'PreferenceNavigationConfig',
|
||||||
|
});
|
||||||
|
|
||||||
|
defineProps<{ disabled?: boolean; disabledNavigationSplit?: boolean }>();
|
||||||
|
|
||||||
|
const navigationStyle = defineModel<string>('navigationStyle');
|
||||||
|
const navigationSplit = defineModel<boolean>('navigationSplit');
|
||||||
|
|
||||||
|
const stylesItems: SelectListItem[] = [
|
||||||
|
{ label: $t('preference.rounded'), value: 'rounded' },
|
||||||
|
{ label: $t('preference.plain'), value: 'plain' },
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ToggleItem
|
||||||
|
v-model="navigationStyle"
|
||||||
|
:items="stylesItems"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
{{ $t('preference.navigation-style') }}
|
||||||
|
</ToggleItem>
|
||||||
|
<SwitchItem v-model="navigationSplit" :disabled="disabledNavigationSplit">
|
||||||
|
{{ $t('preference.navigation-split') }}
|
||||||
|
<template #tip>
|
||||||
|
{{ $t('preference.navigation-split-tip') }}
|
||||||
|
</template>
|
||||||
|
</SwitchItem>
|
||||||
|
</template>
|
|
@ -18,10 +18,13 @@ const sideCollapse = defineModel<boolean>('sideCollapse');
|
||||||
<SwitchItem v-model="sideVisible" :disabled="disabled">
|
<SwitchItem v-model="sideVisible" :disabled="disabled">
|
||||||
{{ $t('preference.side-visible') }}
|
{{ $t('preference.side-visible') }}
|
||||||
</SwitchItem>
|
</SwitchItem>
|
||||||
<SwitchItem v-model="sideCollapse" :disabled="!sideVisible">
|
<SwitchItem v-model="sideCollapse" :disabled="!sideVisible || disabled">
|
||||||
{{ $t('preference.collapse') }}
|
{{ $t('preference.collapse') }}
|
||||||
</SwitchItem>
|
</SwitchItem>
|
||||||
<SwitchItem v-model="sideCollapseShowTitle" :disabled="!sideVisible">
|
<SwitchItem
|
||||||
|
v-model="sideCollapseShowTitle"
|
||||||
|
:disabled="!sideVisible || disabled"
|
||||||
|
>
|
||||||
{{ $t('preference.collapse-show-title') }}
|
{{ $t('preference.collapse-show-title') }}
|
||||||
</SwitchItem>
|
</SwitchItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -53,9 +53,11 @@ function updateLocale(value: string) {
|
||||||
:tabs-icon="preference.tabsIcon"
|
:tabs-icon="preference.tabsIcon"
|
||||||
:locale="preference.locale"
|
:locale="preference.locale"
|
||||||
:navigation-style="preference.navigationStyle"
|
:navigation-style="preference.navigationStyle"
|
||||||
|
:navigation-split="preference.navigationSplit"
|
||||||
:side-collapse-show-title="preference.sideCollapseShowTitle"
|
:side-collapse-show-title="preference.sideCollapseShowTitle"
|
||||||
:page-transition-enable="preference.pageTransitionEnable"
|
:page-transition-enable="preference.pageTransitionEnable"
|
||||||
@update:navigation-style="(value) => handleUpdate('navigationStyle', value)"
|
@update:navigation-style="(value) => handleUpdate('navigationStyle', value)"
|
||||||
|
@update:navigation-split="(value) => handleUpdate('navigationSplit', value)"
|
||||||
@update:dynamic-title="(value) => handleUpdate('dynamicTitle', value)"
|
@update:dynamic-title="(value) => handleUpdate('dynamicTitle', value)"
|
||||||
@update:tabs-icon="(value) => handleUpdate('tabsIcon', value)"
|
@update:tabs-icon="(value) => handleUpdate('tabsIcon', value)"
|
||||||
@update:side-collapse="(value) => handleUpdate('sideCollapse', value)"
|
@update:side-collapse="(value) => handleUpdate('sideCollapse', value)"
|
||||||
|
|
|
@ -53,6 +53,7 @@ const colorWeakMode = defineModel<boolean>('colorWeakMode');
|
||||||
const colorGrayMode = defineModel<boolean>('colorGrayMode');
|
const colorGrayMode = defineModel<boolean>('colorGrayMode');
|
||||||
const colorPrimary = defineModel<string>('colorPrimary');
|
const colorPrimary = defineModel<string>('colorPrimary');
|
||||||
const navigationStyle = defineModel<string>('navigationStyle');
|
const navigationStyle = defineModel<string>('navigationStyle');
|
||||||
|
const navigationSplit = defineModel<boolean>('navigationSplit');
|
||||||
const pageProgress = defineModel<boolean>('pageProgress');
|
const pageProgress = defineModel<boolean>('pageProgress');
|
||||||
const pageTransition = defineModel<string>('pageTransition');
|
const pageTransition = defineModel<string>('pageTransition');
|
||||||
const pageTransitionEnable = defineModel<boolean>('pageTransitionEnable');
|
const pageTransitionEnable = defineModel<boolean>('pageTransitionEnable');
|
||||||
|
@ -67,8 +68,15 @@ const headerMode = defineModel<LayoutHeaderMode>('headerMode');
|
||||||
const footerVisible = defineModel<boolean>('footerVisible');
|
const footerVisible = defineModel<boolean>('footerVisible');
|
||||||
const footerFixed = defineModel<boolean>('footerFixed');
|
const footerFixed = defineModel<boolean>('footerFixed');
|
||||||
|
|
||||||
const { diffPreference, isFullContent, isHeaderNav, isMixedNav, isSideMode } =
|
const {
|
||||||
usePreference();
|
diffPreference,
|
||||||
|
isFullContent,
|
||||||
|
isHeaderNav,
|
||||||
|
isMixedNav,
|
||||||
|
isSideMixedNav,
|
||||||
|
isSideMode,
|
||||||
|
isSideNav,
|
||||||
|
} = usePreference();
|
||||||
const { copy } = useClipboard();
|
const { copy } = useClipboard();
|
||||||
|
|
||||||
const tabs = computed((): SegmentedItem[] => {
|
const tabs = computed((): SegmentedItem[] => {
|
||||||
|
@ -185,6 +193,15 @@ function handleReset() {
|
||||||
/>
|
/>
|
||||||
</Block>
|
</Block>
|
||||||
|
|
||||||
|
<Block :title="$t('preference.navigation-menu')">
|
||||||
|
<Navigation
|
||||||
|
v-model:navigation-style="navigationStyle"
|
||||||
|
v-model:navigation-split="navigationSplit"
|
||||||
|
:disabled="isFullContent"
|
||||||
|
:disabled-navigation-split="!isMixedNav"
|
||||||
|
/>
|
||||||
|
</Block>
|
||||||
|
|
||||||
<Block :title="$t('preference.breadcrumb')">
|
<Block :title="$t('preference.breadcrumb')">
|
||||||
<Breadcrumb
|
<Breadcrumb
|
||||||
v-model:breadcrumb-visible="breadcrumbVisible"
|
v-model:breadcrumb-visible="breadcrumbVisible"
|
||||||
|
@ -192,7 +209,9 @@ function handleReset() {
|
||||||
v-model:breadcrumb-style="breadcrumbStyle"
|
v-model:breadcrumb-style="breadcrumbStyle"
|
||||||
v-model:breadcrumb-home="breadcrumbHome"
|
v-model:breadcrumb-home="breadcrumbHome"
|
||||||
v-model:breadcrumb-hide-only-one="breadcrumbHideOnlyOne"
|
v-model:breadcrumb-hide-only-one="breadcrumbHideOnlyOne"
|
||||||
:disabled="!showBreadcrumbConfig"
|
:disabled="
|
||||||
|
!showBreadcrumbConfig || !(isSideNav || isSideMixedNav)
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</Block>
|
</Block>
|
||||||
|
|
||||||
|
@ -216,12 +235,6 @@ function handleReset() {
|
||||||
v-model:dynamic-title="dynamicTitle"
|
v-model:dynamic-title="dynamicTitle"
|
||||||
/>
|
/>
|
||||||
</Block>
|
</Block>
|
||||||
<Block :title="$t('preference.navigation-menu')">
|
|
||||||
<Navigation
|
|
||||||
v-model:navigation-style="navigationStyle"
|
|
||||||
:disabled="isFullContent"
|
|
||||||
/>
|
|
||||||
</Block>
|
|
||||||
|
|
||||||
<Block :title="$t('preference.animation')">
|
<Block :title="$t('preference.animation')">
|
||||||
<Animation
|
<Animation
|
||||||
|
|
|
@ -17,8 +17,12 @@ function useMixedMenu() {
|
||||||
|
|
||||||
const { isMixedNav } = usePreference();
|
const { isMixedNav } = usePreference();
|
||||||
|
|
||||||
|
const needSplit = computed(
|
||||||
|
() => preference.navigationSplit && isMixedNav.value,
|
||||||
|
);
|
||||||
|
|
||||||
const sideVisible = computed(() => {
|
const sideVisible = computed(() => {
|
||||||
if (isMixedNav.value) {
|
if (needSplit.value) {
|
||||||
return preference.sideVisible && splitSideMenus.value.length > 0;
|
return preference.sideVisible && splitSideMenus.value.length > 0;
|
||||||
}
|
}
|
||||||
return preference.sideVisible;
|
return preference.sideVisible;
|
||||||
|
@ -29,7 +33,7 @@ function useMixedMenu() {
|
||||||
* 头部菜单
|
* 头部菜单
|
||||||
*/
|
*/
|
||||||
const headerMenus = computed(() => {
|
const headerMenus = computed(() => {
|
||||||
if (!isMixedNav.value) {
|
if (!needSplit.value) {
|
||||||
return menus.value;
|
return menus.value;
|
||||||
}
|
}
|
||||||
return menus.value.map((item) => {
|
return menus.value.map((item) => {
|
||||||
|
@ -44,11 +48,7 @@ function useMixedMenu() {
|
||||||
* 侧边菜单
|
* 侧边菜单
|
||||||
*/
|
*/
|
||||||
const sideMenus = computed(() => {
|
const sideMenus = computed(() => {
|
||||||
if (!isMixedNav.value) {
|
return needSplit.value ? splitSideMenus.value : menus.value;
|
||||||
return menus.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return splitSideMenus.value;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,7 +62,7 @@ function useMixedMenu() {
|
||||||
* 头部菜单激活路径
|
* 头部菜单激活路径
|
||||||
*/
|
*/
|
||||||
const headerActive = computed(() => {
|
const headerActive = computed(() => {
|
||||||
if (!isMixedNav.value) {
|
if (!needSplit.value) {
|
||||||
return route.path;
|
return route.path;
|
||||||
}
|
}
|
||||||
return rootMenuPath.value;
|
return rootMenuPath.value;
|
||||||
|
@ -74,7 +74,7 @@ function useMixedMenu() {
|
||||||
* @param mode 菜单模式
|
* @param mode 菜单模式
|
||||||
*/
|
*/
|
||||||
const handleMenuSelect = (key: string, mode?: string) => {
|
const handleMenuSelect = (key: string, mode?: string) => {
|
||||||
if (!isMixedNav.value || mode === 'vertical') {
|
if (!needSplit.value || mode === 'vertical') {
|
||||||
navigation(key);
|
navigation(key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,11 +71,14 @@ preference:
|
||||||
language: Language
|
language: Language
|
||||||
dynamic-title: Dynamic Title
|
dynamic-title: Dynamic Title
|
||||||
normal: Normal
|
normal: Normal
|
||||||
|
plain: Plain
|
||||||
rounded: Rounded
|
rounded: Rounded
|
||||||
collapse: Collpase Menu
|
collapse: Collpase Menu
|
||||||
collapse-show-title: Display menu name
|
collapse-show-title: Display menu name
|
||||||
navigation-menu: Navigation Menu
|
navigation-menu: Navigation Menu
|
||||||
navigation-style: Navigation menu style
|
navigation-style: Navigation menu style
|
||||||
|
navigation-split: Navigation Menu Separation
|
||||||
|
navigation-split-tip: When enabled, the sidebar shows the top bar's submenu
|
||||||
interface-control: Interface Layout Control
|
interface-control: Interface Layout Control
|
||||||
breadcrumb: Breadcrumb
|
breadcrumb: Breadcrumb
|
||||||
breadcrumb-home: Display the home button
|
breadcrumb-home: Display the home button
|
||||||
|
|
|
@ -73,9 +73,12 @@ preference:
|
||||||
animation: 动画
|
animation: 动画
|
||||||
navigation-menu: 导航菜单
|
navigation-menu: 导航菜单
|
||||||
navigation-style: 导航菜单风格
|
navigation-style: 导航菜单风格
|
||||||
|
navigation-split: 导航菜单分离
|
||||||
|
navigation-split-tip: 开启时,侧边栏显示顶栏对应菜单的子菜单
|
||||||
interface-control: 界面布局控制
|
interface-control: 界面布局控制
|
||||||
normal: 默认
|
normal: 默认
|
||||||
rounded: 圆角
|
plain: 朴素
|
||||||
|
rounded: 圆润
|
||||||
breadcrumb: 面包屑导航
|
breadcrumb: 面包屑导航
|
||||||
breadcrumb-enable: 开启面包屑导航
|
breadcrumb-enable: 开启面包屑导航
|
||||||
breadcrumb-icon: 显示面包屑图标
|
breadcrumb-icon: 显示面包屑图标
|
||||||
|
|
|
@ -27,6 +27,7 @@ const defaultPreference: Preference = {
|
||||||
locale: 'zh-CN',
|
locale: 'zh-CN',
|
||||||
logo: 'https://cdn.jsdelivr.net/gh/vbenjs/vben-cdn-static@0.1.2/vben-admin/admin-logo.png',
|
logo: 'https://cdn.jsdelivr.net/gh/vbenjs/vben-cdn-static@0.1.2/vben-admin/admin-logo.png',
|
||||||
logoVisible: true,
|
logoVisible: true,
|
||||||
|
navigationSplit: true,
|
||||||
navigationStyle: 'rounded',
|
navigationStyle: 'rounded',
|
||||||
pageProgress: true,
|
pageProgress: true,
|
||||||
pageTransition: 'fade-slide',
|
pageTransition: 'fade-slide',
|
||||||
|
|
Loading…
Reference in New Issue