-
Notifications
You must be signed in to change notification settings - Fork 2.4k
feat(projects): hybrid layout mode auto select first deepest child menu #863
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,13 +3,15 @@ import { useRoute } from 'vue-router'; | |||||||||||||||||||||||
| import { useContext } from '@sa/hooks'; | ||||||||||||||||||||||||
| import type { RouteKey } from '@elegant-router/types'; | ||||||||||||||||||||||||
| import { useRouteStore } from '@/store/modules/route'; | ||||||||||||||||||||||||
| import { useThemeStore } from '@/store/modules/theme'; | ||||||||||||||||||||||||
| import { useRouterPush } from '@/hooks/common/router'; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| export const [provideMixMenuContext, useMixMenuContext] = useContext('MixMenu', useMixMenu); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| function useMixMenu() { | ||||||||||||||||||||||||
| const route = useRoute(); | ||||||||||||||||||||||||
| const routeStore = useRouteStore(); | ||||||||||||||||||||||||
| const themeStore = useThemeStore(); | ||||||||||||||||||||||||
| const { selectedKey } = useMenu(); | ||||||||||||||||||||||||
| const { routerPushByKeyWithMetaQuery } = useRouterPush(); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
@@ -100,10 +102,46 @@ function useMixMenu() { | |||||||||||||||||||||||
| () => secondLevelMenus.value.find(menu => menu.key === activeSecondLevelMenuKey.value)?.children || [] | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const hasChildLevelMenus = computed(() => childLevelMenus.value.length > 0); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| function getDeepestLevelMenuKey(): RouteKey | null { | ||||||||||||||||||||||||
| if (!secondLevelMenus.value.length || !themeStore.sider.autoSelectFirstMenu) { | ||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const secondLevelFirstMenu = secondLevelMenus.value[0]; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if (!secondLevelFirstMenu) { | ||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| function findDeepest(menu: App.Global.Menu): RouteKey { | ||||||||||||||||||||||||
| if (!menu.children?.length) { | ||||||||||||||||||||||||
| return menu.routeKey; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| return findDeepest(menu.children[0]); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| return findDeepest(secondLevelFirstMenu); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| function activeDeepestLevelMenuKey() { | ||||||||||||||||||||||||
| const deepestLevelMenuKey = getDeepestLevelMenuKey(); | ||||||||||||||||||||||||
| if (!deepestLevelMenuKey) return; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // select the deepest second level menu | ||||||||||||||||||||||||
| handleSelectSecondLevelMenu(deepestLevelMenuKey); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| watch( | ||||||||||||||||||||||||
| () => route.name, | ||||||||||||||||||||||||
| () => { | ||||||||||||||||||||||||
| getActiveFirstLevelMenuKey(); | ||||||||||||||||||||||||
| // if there are child level menus, get the active second level menu key | ||||||||||||||||||||||||
| if (hasChildLevelMenus.value) { | ||||||||||||||||||||||||
| getActiveSecondLevelMenuKey(); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
Comment on lines
+141
to
+144
|
||||||||||||||||||||||||
| // if there are child level menus, get the active second level menu key | |
| if (hasChildLevelMenus.value) { | |
| getActiveSecondLevelMenuKey(); | |
| } | |
| // always get the active second level menu key when the route changes | |
| getActiveSecondLevelMenuKey(); |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment "if there are child level menus, get the active second level menu key" is misleading. The condition checks whether the OLD active second-level menu has children (using stale state), not whether we need to update the active second-level menu for the NEW route.
Update the comment to clarify this is checking for child level menus before updating, or remove the condition altogether as suggested in the related bug comment.
| // if there are child level menus, get the active second level menu key | |
| if (hasChildLevelMenus.value) { | |
| getActiveSecondLevelMenuKey(); | |
| } | |
| getActiveSecondLevelMenuKey(); |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |||||
| import { ref, watch } from 'vue'; | ||||||
| import { useRoute } from 'vue-router'; | ||||||
| import { SimpleScrollbar } from '@sa/materials'; | ||||||
| import type { RouteKey } from '@elegant-router/types'; | ||||||
| import { GLOBAL_HEADER_MENU_ID, GLOBAL_SIDER_MENU_ID } from '@/constants/app'; | ||||||
| import { useAppStore } from '@/store/modules/app'; | ||||||
| import { useThemeStore } from '@/store/modules/theme'; | ||||||
|
|
@@ -18,12 +19,28 @@ const appStore = useAppStore(); | |||||
| const themeStore = useThemeStore(); | ||||||
| const routeStore = useRouteStore(); | ||||||
| const { routerPushByKeyWithMetaQuery } = useRouterPush(); | ||||||
| const { firstLevelMenus, secondLevelMenus, activeFirstLevelMenuKey, handleSelectFirstLevelMenu } = | ||||||
| useMixMenuContext('TopHybridHeaderFirst'); | ||||||
| const { | ||||||
| firstLevelMenus, | ||||||
| secondLevelMenus, | ||||||
| activeFirstLevelMenuKey, | ||||||
| handleSelectFirstLevelMenu, | ||||||
| activeDeepestLevelMenuKey | ||||||
| } = useMixMenuContext('TopHybridHeaderFirst'); | ||||||
| const { selectedKey } = useMenu(); | ||||||
|
|
||||||
| const expandedKeys = ref<string[]>([]); | ||||||
|
|
||||||
| /** | ||||||
| * Handle first level menu select | ||||||
| * @param key RouteKey | ||||||
| */ | ||||||
| function handleSelectMenu(key: RouteKey) { | ||||||
| handleSelectFirstLevelMenu(key); | ||||||
|
|
||||||
| // if there are second level menus, select the deepest one by default | ||||||
|
||||||
| // if there are second level menus, select the deepest one by default | |
| // if there are second level menus and autoSelectFirstMenu is enabled, select the deepest one |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,4 +1,5 @@ | ||||||
| <script setup lang="ts"> | ||||||
| import type { RouteKey } from '@elegant-router/types'; | ||||||
| import { GLOBAL_HEADER_MENU_ID, GLOBAL_SIDER_MENU_ID } from '@/constants/app'; | ||||||
| import { useAppStore } from '@/store/modules/app'; | ||||||
| import { useThemeStore } from '@/store/modules/theme'; | ||||||
|
|
@@ -13,9 +14,25 @@ defineOptions({ | |||||
| const appStore = useAppStore(); | ||||||
| const themeStore = useThemeStore(); | ||||||
| const { routerPushByKeyWithMetaQuery } = useRouterPush(); | ||||||
| const { firstLevelMenus, secondLevelMenus, activeFirstLevelMenuKey, handleSelectFirstLevelMenu } = | ||||||
| useMixMenuContext('TopHybridSidebarFirst'); | ||||||
| const { | ||||||
| firstLevelMenus, | ||||||
| secondLevelMenus, | ||||||
| activeFirstLevelMenuKey, | ||||||
| handleSelectFirstLevelMenu, | ||||||
| activeDeepestLevelMenuKey | ||||||
| } = useMixMenuContext('TopHybridSidebarFirst'); | ||||||
| const { selectedKey } = useMenu(); | ||||||
|
|
||||||
| /** | ||||||
| * Handle first level menu select | ||||||
| * @param key RouteKey | ||||||
| */ | ||||||
| function handleSelectMenu(key: RouteKey) { | ||||||
| handleSelectFirstLevelMenu(key); | ||||||
|
|
||||||
| // if there are second level menus, select the deepest one by default | ||||||
|
||||||
| // if there are second level menus, select the deepest one by default | |
| // if there are second level menus and autoSelectFirstMenu is enabled, select the deepest one |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment "select the deepest second level menu" is misleading. The function actually navigates to the deepest menu at any level (could be second, third, fourth level, etc.), not specifically the second level.
Consider updating to "navigate to the deepest menu" or "select and navigate to the deepest level menu" for clarity.