Skip to content

Commit

Permalink
refactor(projects)!: refactor global menu & support reversed-horizont…
Browse files Browse the repository at this point in the history
…al-mix-menu
  • Loading branch information
honghuangdc committed Sep 8, 2024
1 parent 47c46e3 commit 2244f0c
Show file tree
Hide file tree
Showing 27 changed files with 667 additions and 384 deletions.
4 changes: 4 additions & 0 deletions src/constants/app.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { transformRecordToOption } from '@/utils/common';

export const GLOBAL_HEADER_MENU_ID = '__GLOBAL_HEADER_MENU__';

export const GLOBAL_SIDER_MENU_ID = '__GLOBAL_SIDER_MENU__';

export const themeSchemaRecord: Record<UnionKey.ThemeScheme, App.I18n.I18nKey> = {
light: 'theme.themeSchema.light',
dark: 'theme.themeSchema.dark',
Expand Down
18 changes: 16 additions & 2 deletions src/hooks/common/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,30 @@ export function useRouterPush(inSetup = true) {
name: key
};

if (query) {
if (Object.keys(query || {}).length) {
routeLocation.query = query;
}

if (params) {
if (Object.keys(params || {}).length) {
routeLocation.params = params;
}

return routerPush(routeLocation);
}

function routerPushByKeyWithMetaQuery(key: RouteKey) {
const allRoutes = router.getRoutes();
const meta = allRoutes.find(item => item.name === key)?.meta || null;

const query: Record<string, string> = {};

meta?.query?.forEach(item => {
query[item.key] = item.value;
});

return routerPushByKey(key, { query });
}

async function toHome() {
return routerPushByKey('root');
}
Expand Down Expand Up @@ -95,6 +108,7 @@ export function useRouterPush(inSetup = true) {
routerPush,
routerBack,
routerPushByKey,
routerPushByKeyWithMetaQuery,
toLogin,
toggleLoginModule,
redirectFromLogin
Expand Down
68 changes: 40 additions & 28 deletions src/layouts/base-layout/index.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed } from 'vue';
import { computed, defineAsyncComponent } from 'vue';
import { AdminLayout, LAYOUT_SCROLL_EL_ID } from '@sa/materials';
import type { LayoutMode } from '@sa/materials';
import { useAppStore } from '@/store/modules/app';
Expand All @@ -18,38 +18,44 @@ defineOptions({
const appStore = useAppStore();
const themeStore = useThemeStore();
const { menus } = setupMixMenuContext();
const { childLevelMenus, isActiveFirstLevelMenuHasChildren } = setupMixMenuContext();
const GlobalMenu = defineAsyncComponent(() => import('../modules/global-menu/index.vue'));
const layoutMode = computed(() => {
const vertical: LayoutMode = 'vertical';
const horizontal: LayoutMode = 'horizontal';
return themeStore.layout.mode.includes(vertical) ? vertical : horizontal;
});
const headerPropsConfig: Record<UnionKey.ThemeLayoutMode, App.Global.HeaderProps> = {
vertical: {
showLogo: false,
showMenu: false,
showMenuToggler: true
},
'vertical-mix': {
showLogo: false,
showMenu: false,
showMenuToggler: false
},
horizontal: {
showLogo: true,
showMenu: true,
showMenuToggler: false
},
'horizontal-mix': {
showLogo: true,
showMenu: true,
showMenuToggler: false
}
};
const headerProps = computed(() => headerPropsConfig[themeStore.layout.mode]);
const headerProps = computed(() => {
const { mode, reverseHorizontalMix } = themeStore.layout;
const headerPropsConfig: Record<UnionKey.ThemeLayoutMode, App.Global.HeaderProps> = {
vertical: {
showLogo: false,
showMenu: false,
showMenuToggler: true
},
'vertical-mix': {
showLogo: false,
showMenu: false,
showMenuToggler: false
},
horizontal: {
showLogo: true,
showMenu: true,
showMenuToggler: false
},
'horizontal-mix': {
showLogo: true,
showMenu: true,
showMenuToggler: reverseHorizontalMix && isActiveFirstLevelMenuHasChildren.value
}
};
return headerPropsConfig[mode];
});
const siderVisible = computed(() => themeStore.layout.mode !== 'horizontal');
Expand All @@ -62,11 +68,16 @@ const siderWidth = computed(() => getSiderWidth());
const siderCollapsedWidth = computed(() => getSiderCollapsedWidth());
function getSiderWidth() {
const { reverseHorizontalMix } = themeStore.layout;
const { width, mixWidth, mixChildMenuWidth } = themeStore.sider;
if (isHorizontalMix.value && reverseHorizontalMix) {
return isActiveFirstLevelMenuHasChildren.value ? width : 0;
}
let w = isVerticalMix.value || isHorizontalMix.value ? mixWidth : width;
if (isVerticalMix.value && appStore.mixSiderFixed && menus.value.length) {
if (isVerticalMix.value && appStore.mixSiderFixed && childLevelMenus.value.length) {
w += mixChildMenuWidth;
}
Expand All @@ -78,7 +89,7 @@ function getSiderCollapsedWidth() {
let w = isVerticalMix.value || isHorizontalMix.value ? mixCollapsedWidth : collapsedWidth;
if (isVerticalMix.value && appStore.mixSiderFixed && menus.value.length) {
if (isVerticalMix.value && appStore.mixSiderFixed && childLevelMenus.value.length) {
w += mixChildMenuWidth;
}
Expand Down Expand Up @@ -116,6 +127,7 @@ function getSiderCollapsedWidth() {
<template #sider>
<GlobalSider />
</template>
<GlobalMenu />
<GlobalContent />
<ThemeDrawer />
<template #footer>
Expand Down
54 changes: 45 additions & 9 deletions src/layouts/context/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const { setupStore: setupMixMenuContext, useStore: useMixMenuContext } =
function useMixMenu() {
const route = useRoute();
const routeStore = useRouteStore();
const { selectedKey } = useMenu();

const activeFirstLevelMenuKey = ref('');

Expand All @@ -16,20 +17,35 @@ function useMixMenu() {
}

function getActiveFirstLevelMenuKey() {
const { hideInMenu, activeMenu } = route.meta;
const name = route.name as string;

const routeName = (hideInMenu ? activeMenu : name) || name;

const [firstLevelRouteName] = routeName.split('_');
const [firstLevelRouteName] = selectedKey.value.split('_');

setActiveFirstLevelMenuKey(firstLevelRouteName);
}

const menus = computed(
const allMenus = computed<App.Global.Menu[]>(() => routeStore.menus);

const firstLevelMenus = computed<App.Global.Menu[]>(() =>
routeStore.menus.map(menu => {
const { children: _, ...rest } = menu;

return rest;
})
);

const childLevelMenus = computed<App.Global.Menu[]>(
() => routeStore.menus.find(menu => menu.key === activeFirstLevelMenuKey.value)?.children || []
);

const isActiveFirstLevelMenuHasChildren = computed(() => {
if (!activeFirstLevelMenuKey.value) {
return false;
}

const findItem = allMenus.value.find(item => item.key === activeFirstLevelMenuKey.value);

return Boolean(findItem?.children?.length);
});

watch(
() => route.name,
() => {
Expand All @@ -39,9 +55,29 @@ function useMixMenu() {
);

return {
allMenus,
firstLevelMenus,
childLevelMenus,
isActiveFirstLevelMenuHasChildren,
activeFirstLevelMenuKey,
setActiveFirstLevelMenuKey,
getActiveFirstLevelMenuKey,
menus
getActiveFirstLevelMenuKey
};
}

export function useMenu() {
const route = useRoute();

const selectedKey = computed(() => {
const { hideInMenu, activeMenu } = route.meta;
const name = route.name as string;

const routeName = (hideInMenu ? activeMenu : name) || name;

return routeName;
});

return {
selectedKey
};
}
23 changes: 3 additions & 20 deletions src/layouts/modules/global-header/index.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
<script setup lang="ts">
import { computed } from 'vue';
import { useFullscreen } from '@vueuse/core';
import { useAppStore } from '@/store/modules/app';
import { useThemeStore } from '@/store/modules/theme';
import { useRouteStore } from '@/store/modules/route';
import HorizontalMenu from '../global-menu/base-menu.vue';
import { GLOBAL_HEADER_MENU_ID } from '@/constants/app';
import GlobalLogo from '../global-logo/index.vue';
import GlobalBreadcrumb from '../global-breadcrumb/index.vue';
import { useMixMenuContext } from '../../context';
import ThemeButton from './components/theme-button.vue';
import UserAvatar from './components/user-avatar.vue';
Expand All @@ -28,29 +25,15 @@ defineProps<Props>();
const appStore = useAppStore();
const themeStore = useThemeStore();
const routeStore = useRouteStore();
const { isFullscreen, toggle } = useFullscreen();
const { menus } = useMixMenuContext();
const headerMenus = computed(() => {
if (themeStore.layout.mode === 'horizontal') {
return routeStore.menus;
}
if (themeStore.layout.mode === 'horizontal-mix') {
return menus.value;
}
return [];
});
</script>

<template>
<DarkModeContainer class="h-full flex-y-center px-12px shadow-header">
<GlobalLogo v-if="showLogo" class="h-full" :style="{ width: themeStore.sider.width + 'px' }" />
<HorizontalMenu v-if="showMenu" mode="horizontal" :menus="headerMenus" class="px-12px" />
<MenuToggler v-if="showMenuToggler" :collapsed="appStore.siderCollapse" @click="appStore.toggleSiderCollapse" />
<div v-if="showMenu" :id="GLOBAL_HEADER_MENU_ID" class="h-full flex-y-center flex-1-hidden pb-1px"></div>
<div v-else class="h-full flex-y-center flex-1-hidden">
<MenuToggler v-if="showMenuToggler" :collapsed="appStore.siderCollapse" @click="appStore.toggleSiderCollapse" />
<GlobalBreadcrumb v-if="!appStore.isMobile" class="ml-12px" />
</div>
<div class="h-full flex-y-center justify-end">
Expand Down
Loading

0 comments on commit 2244f0c

Please sign in to comment.