Skip to content

Commit dab5333

Browse files
committed
refactor(projects): the vercal-mix reconstruction is complete
1 parent b9b55d3 commit dab5333

File tree

8 files changed

+303
-36
lines changed

8 files changed

+303
-36
lines changed

src/layouts/base-layout/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ export function Component() {
7777
[activeFirstLevelMenuKey, menus]
7878
);
7979

80+
console.log(childrenMenu);
81+
8082
function getSiderWidth() {
8183
const { width, mixWidth, mixChildMenuWidth } = themeSettings.sider;
8284

@@ -150,6 +152,7 @@ export function Component() {
150152
<GlobalContent />
151153
<Suspense fallback={null}>
152154
<GlobalMenu
155+
childrenMenu={childrenMenu}
153156
mode={themeSettings.layout.mode}
154157
menus={menus}
155158
/>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import type { Route } from '@sa/simple-router';
2+
import type { MenuInfo } from 'rc-menu/lib/interface';
3+
import { useRouterPush } from '@/hooks/common/routerPush';
4+
5+
function getSelectKey(route: Route) {
6+
const { hideInMenu, activeMenu } = route.meta;
7+
8+
const name = route.name as string;
9+
10+
const routeName = (hideInMenu ? activeMenu : name) || name;
11+
12+
return [routeName];
13+
}
14+
15+
const HorizontalMenu = () => {
16+
const route = useRoute();
17+
18+
const menus = useMenu();
19+
20+
const router = useRouterPush();
21+
22+
const selectKey = getSelectKey(route);
23+
24+
function handleClickMenu(menuInfo: MenuInfo) {
25+
router.menuPush(menuInfo.key);
26+
}
27+
28+
return (
29+
<AMenu
30+
mode="horizontal"
31+
items={menus}
32+
inlineIndent={18}
33+
onSelect={handleClickMenu}
34+
selectedKeys={selectKey}
35+
/>
36+
);
37+
};
38+
39+
export default HorizontalMenu;
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import { SimpleScrollbar } from '@sa/materials';
2+
import type { Route, RouteRecordNormalized } from '@sa/simple-router';
3+
import type { MenuInfo } from 'rc-menu/lib/interface';
4+
import type { MenuProps } from 'antd';
5+
import { getSiderCollapse } from '@/store/slice/app';
6+
import { getThemeSettings } from '@/store/slice/theme';
7+
8+
interface LevelKeysProps {
9+
key?: string;
10+
children?: LevelKeysProps[];
11+
}
12+
13+
const getLevelKeys = (items1: LevelKeysProps[]) => {
14+
const key: Record<string, number> = {};
15+
const func = (items2: LevelKeysProps[], level = 1) => {
16+
items2.forEach(item => {
17+
if (item.key) {
18+
key[item.key] = level;
19+
}
20+
if (item.children) {
21+
func(item.children, level + 1);
22+
}
23+
});
24+
};
25+
func(items1);
26+
return key;
27+
};
28+
29+
function getSelectKey(route: Route) {
30+
const { hideInMenu, activeMenu } = route.meta;
31+
32+
const name = route.name as string;
33+
34+
const routeName = (hideInMenu ? activeMenu : name) || name;
35+
36+
return [routeName];
37+
}
38+
39+
const getSelectedMenuKeyPath = (matches: RouteRecordNormalized[]) => {
40+
const result = matches.reduce((acc: string[], match, index) => {
41+
if (index < matches.length - 1 && match.name) {
42+
acc.push(match.name);
43+
}
44+
return acc;
45+
}, []);
46+
47+
return result;
48+
};
49+
50+
const VerticalMenu = memo(() => {
51+
const menus = useMenu();
52+
53+
const route = useRoute();
54+
const levelKeys = getLevelKeys(menus as LevelKeysProps[]);
55+
56+
const themeSettings = useAppSelector(getThemeSettings);
57+
58+
const selectedKeys = getSelectKey(route);
59+
60+
const router = useRouterPush();
61+
const matches = route.matched;
62+
const openKeys = () => {
63+
return getSelectedMenuKeyPath(matches);
64+
};
65+
66+
const inlineCollapsed = useAppSelector(getSiderCollapse);
67+
68+
const [stateOpenKeys, setStateOpenKeys] = useState<string[]>(openKeys());
69+
70+
function handleClickMenu(menuInfo: MenuInfo) {
71+
router.menuPush(menuInfo.key);
72+
}
73+
74+
const onOpenChange: MenuProps['onOpenChange'] = keys => {
75+
if (keys.includes('rc-menu-more')) {
76+
setStateOpenKeys(keys);
77+
return;
78+
}
79+
80+
const currentOpenKey = keys.find(key => !stateOpenKeys.includes(key));
81+
82+
// open
83+
if (currentOpenKey && themeSettings.isOnlyExpandCurrentParentMenu) {
84+
const repeatIndex = keys
85+
.filter(key => key !== currentOpenKey)
86+
.findIndex(key => levelKeys[key] === levelKeys[currentOpenKey]);
87+
88+
setStateOpenKeys(
89+
keys
90+
// remove repeat key
91+
.filter((_, index) => index !== repeatIndex)
92+
// remove current level all child
93+
.filter(key => levelKeys[key] <= levelKeys[currentOpenKey])
94+
);
95+
} else {
96+
// close
97+
setStateOpenKeys(keys);
98+
}
99+
};
100+
101+
return (
102+
<SimpleScrollbar>
103+
<AMenu
104+
mode="inline"
105+
items={menus}
106+
inlineCollapsed={inlineCollapsed}
107+
openKeys={stateOpenKeys}
108+
onOpenChange={onOpenChange}
109+
selectedKeys={selectedKeys}
110+
onSelect={handleClickMenu}
111+
className="size-full bg-container transition-300 border-0!"
112+
inlineIndent={18}
113+
/>
114+
</SimpleScrollbar>
115+
);
116+
});
117+
118+
export default VerticalMenu;

src/layouts/modules/global-menu/index.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,24 @@ import { GLOBAL_HEADER_MENU_ID, GLOBAL_SIDER_MENU_ID } from '@/constants/app';
44
import VerticalMixMenu from './modules/VerticalMixMenu';
55
import HorizontalMenu from './modules/HorizontalMenu';
66
import HorizontalMixMenu from './modules/HorizontalMixMenu';
7+
import VerticalMenu from './modules/VerticalMenu';
78

89
interface Props {
910
mode: UnionKey.ThemeLayoutMode;
1011
menus: MenuProps['items'];
12+
childrenMenu: MenuProps['items'];
1113
}
1214

1315
const headerContainer = document.getElementById(GLOBAL_HEADER_MENU_ID);
1416

1517
const siderContainer = document.getElementById(GLOBAL_SIDER_MENU_ID);
1618

17-
const GlobalMenu: FC<Props> = memo(({ mode, menus }) => {
19+
const GlobalMenu: FC<Props> = memo(({ mode, menus, childrenMenu }) => {
1820
if (!headerContainer || !siderContainer) return null;
1921

2022
const componentsMap = {
21-
vertical: createPortal(<VerticalMixMenu menus={menus} />, siderContainer),
22-
'vertical-mix': <VerticalMixMenu menus={menus} />,
23+
vertical: createPortal(<VerticalMenu menus={menus} />, siderContainer),
24+
'vertical-mix': createPortal(<VerticalMixMenu menus={childrenMenu} />, siderContainer),
2325
horizontal: createPortal(<HorizontalMenu />, headerContainer),
2426
'horizontal-mix': <HorizontalMixMenu />
2527
};

src/layouts/modules/global-menu/modules/HorizontalMenu.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const HorizontalMenu = () => {
2727
}
2828

2929
if (!headerContainer) return null;
30+
3031
return (
3132
<AMenu
3233
mode="horizontal"

src/layouts/modules/global-menu/modules/HorizontalMixMenu.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ const HorizontalMixMenu = memo(() => {
3838
}
3939
}
4040
if (!headerContainer || !siderContainer) return null;
41+
console.log(siderContainer);
42+
4143
return (
4244
<>
4345
{createPortal(
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { SimpleScrollbar } from '@sa/materials';
2+
import type { Route, RouteRecordNormalized } from '@sa/simple-router';
3+
import type { MenuInfo } from 'rc-menu/lib/interface';
4+
import type { MenuProps } from 'antd';
5+
import { getSiderCollapse } from '@/store/slice/app';
6+
import { getThemeSettings } from '@/store/slice/theme';
7+
8+
interface LevelKeysProps {
9+
key?: string;
10+
children?: LevelKeysProps[];
11+
}
12+
13+
interface Props {
14+
menus: MenuProps['items'];
15+
}
16+
17+
const getLevelKeys = (items1: LevelKeysProps[]) => {
18+
const key: Record<string, number> = {};
19+
20+
if (!items1) return key;
21+
const func = (items2: LevelKeysProps[], level = 1) => {
22+
items2.forEach(item => {
23+
if (item.key) {
24+
key[item.key] = level;
25+
}
26+
if (item.children) {
27+
func(item.children, level + 1);
28+
}
29+
});
30+
};
31+
func(items1);
32+
return key;
33+
};
34+
35+
function getSelectKey(route: Route) {
36+
const { hideInMenu, activeMenu } = route.meta;
37+
38+
const name = route.name as string;
39+
40+
const routeName = (hideInMenu ? activeMenu : name) || name;
41+
42+
return [routeName];
43+
}
44+
45+
const getSelectedMenuKeyPath = (matches: RouteRecordNormalized[]) => {
46+
const result = matches.reduce((acc: string[], match, index) => {
47+
if (index < matches.length - 1 && match.name) {
48+
acc.push(match.name);
49+
}
50+
return acc;
51+
}, []);
52+
53+
return result;
54+
};
55+
56+
const VerticalMenu: FC<Props> = memo(({ menus }) => {
57+
console.log(menus);
58+
59+
const route = useRoute();
60+
const levelKeys = getLevelKeys(menus as LevelKeysProps[]);
61+
62+
const themeSettings = useAppSelector(getThemeSettings);
63+
64+
const selectedKeys = getSelectKey(route);
65+
66+
const router = useRouterPush();
67+
const matches = route.matched;
68+
const openKeys = () => {
69+
return getSelectedMenuKeyPath(matches);
70+
};
71+
72+
const inlineCollapsed = useAppSelector(getSiderCollapse);
73+
74+
const siderCollapse = themeSettings.layout.mode === 'vertical-mix' ? false : inlineCollapsed;
75+
76+
const [stateOpenKeys, setStateOpenKeys] = useState<string[]>(openKeys());
77+
78+
function handleClickMenu(menuInfo: MenuInfo) {
79+
router.menuPush(menuInfo.key);
80+
}
81+
82+
const onOpenChange: MenuProps['onOpenChange'] = keys => {
83+
if (keys.includes('rc-menu-more')) {
84+
setStateOpenKeys(keys);
85+
return;
86+
}
87+
88+
const currentOpenKey = keys.find(key => !stateOpenKeys.includes(key));
89+
90+
// open
91+
if (currentOpenKey && themeSettings.isOnlyExpandCurrentParentMenu) {
92+
const repeatIndex = keys
93+
.filter(key => key !== currentOpenKey)
94+
.findIndex(key => levelKeys[key] === levelKeys[currentOpenKey]);
95+
96+
setStateOpenKeys(
97+
keys
98+
// remove repeat key
99+
.filter((_, index) => index !== repeatIndex)
100+
// remove current level all child
101+
.filter(key => levelKeys[key] <= levelKeys[currentOpenKey])
102+
);
103+
} else {
104+
// close
105+
setStateOpenKeys(keys);
106+
}
107+
};
108+
109+
return (
110+
<SimpleScrollbar>
111+
<AMenu
112+
mode="inline"
113+
items={menus}
114+
inlineCollapsed={siderCollapse}
115+
openKeys={stateOpenKeys}
116+
onOpenChange={onOpenChange}
117+
selectedKeys={selectedKeys}
118+
onSelect={handleClickMenu}
119+
className="size-full bg-container transition-300 border-0!"
120+
inlineIndent={18}
121+
/>
122+
</SimpleScrollbar>
123+
);
124+
});
125+
126+
export default VerticalMenu;

0 commit comments

Comments
 (0)