Skip to content

Commit

Permalink
refactor(projects): the vercal-mix reconstruction is complete
Browse files Browse the repository at this point in the history
  • Loading branch information
mufeng889 committed Sep 4, 2024
1 parent b9b55d3 commit dab5333
Show file tree
Hide file tree
Showing 8 changed files with 303 additions and 36 deletions.
3 changes: 3 additions & 0 deletions src/layouts/base-layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export function Component() {
[activeFirstLevelMenuKey, menus]
);

console.log(childrenMenu);

function getSiderWidth() {
const { width, mixWidth, mixChildMenuWidth } = themeSettings.sider;

Expand Down Expand Up @@ -150,6 +152,7 @@ export function Component() {
<GlobalContent />
<Suspense fallback={null}>
<GlobalMenu
childrenMenu={childrenMenu}
mode={themeSettings.layout.mode}
menus={menus}
/>
Expand Down
39 changes: 39 additions & 0 deletions src/layouts/modules/global-menu/components/HorizontalMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { Route } from '@sa/simple-router';
import type { MenuInfo } from 'rc-menu/lib/interface';
import { useRouterPush } from '@/hooks/common/routerPush';

function getSelectKey(route: Route) {
const { hideInMenu, activeMenu } = route.meta;

const name = route.name as string;

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

return [routeName];
}

const HorizontalMenu = () => {
const route = useRoute();

const menus = useMenu();

const router = useRouterPush();

const selectKey = getSelectKey(route);

function handleClickMenu(menuInfo: MenuInfo) {
router.menuPush(menuInfo.key);
}

return (
<AMenu
mode="horizontal"
items={menus}
inlineIndent={18}
onSelect={handleClickMenu}
selectedKeys={selectKey}
/>
);
};

export default HorizontalMenu;
118 changes: 118 additions & 0 deletions src/layouts/modules/global-menu/components/VerticalMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { SimpleScrollbar } from '@sa/materials';
import type { Route, RouteRecordNormalized } from '@sa/simple-router';
import type { MenuInfo } from 'rc-menu/lib/interface';
import type { MenuProps } from 'antd';
import { getSiderCollapse } from '@/store/slice/app';
import { getThemeSettings } from '@/store/slice/theme';

interface LevelKeysProps {
key?: string;
children?: LevelKeysProps[];
}

const getLevelKeys = (items1: LevelKeysProps[]) => {
const key: Record<string, number> = {};
const func = (items2: LevelKeysProps[], level = 1) => {
items2.forEach(item => {
if (item.key) {
key[item.key] = level;
}
if (item.children) {
func(item.children, level + 1);
}
});
};
func(items1);
return key;
};

function getSelectKey(route: Route) {
const { hideInMenu, activeMenu } = route.meta;

const name = route.name as string;

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

return [routeName];
}

const getSelectedMenuKeyPath = (matches: RouteRecordNormalized[]) => {
const result = matches.reduce((acc: string[], match, index) => {
if (index < matches.length - 1 && match.name) {
acc.push(match.name);
}
return acc;
}, []);

return result;
};

const VerticalMenu = memo(() => {
const menus = useMenu();

const route = useRoute();
const levelKeys = getLevelKeys(menus as LevelKeysProps[]);

const themeSettings = useAppSelector(getThemeSettings);

const selectedKeys = getSelectKey(route);

const router = useRouterPush();
const matches = route.matched;
const openKeys = () => {
return getSelectedMenuKeyPath(matches);
};

const inlineCollapsed = useAppSelector(getSiderCollapse);

const [stateOpenKeys, setStateOpenKeys] = useState<string[]>(openKeys());

function handleClickMenu(menuInfo: MenuInfo) {
router.menuPush(menuInfo.key);
}

const onOpenChange: MenuProps['onOpenChange'] = keys => {
if (keys.includes('rc-menu-more')) {
setStateOpenKeys(keys);
return;
}

const currentOpenKey = keys.find(key => !stateOpenKeys.includes(key));

// open
if (currentOpenKey && themeSettings.isOnlyExpandCurrentParentMenu) {
const repeatIndex = keys
.filter(key => key !== currentOpenKey)
.findIndex(key => levelKeys[key] === levelKeys[currentOpenKey]);

setStateOpenKeys(
keys
// remove repeat key
.filter((_, index) => index !== repeatIndex)
// remove current level all child
.filter(key => levelKeys[key] <= levelKeys[currentOpenKey])
);
} else {
// close
setStateOpenKeys(keys);
}
};

return (
<SimpleScrollbar>
<AMenu
mode="inline"
items={menus}
inlineCollapsed={inlineCollapsed}
openKeys={stateOpenKeys}
onOpenChange={onOpenChange}
selectedKeys={selectedKeys}
onSelect={handleClickMenu}
className="size-full bg-container transition-300 border-0!"
inlineIndent={18}
/>
</SimpleScrollbar>
);
});

export default VerticalMenu;
8 changes: 5 additions & 3 deletions src/layouts/modules/global-menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@ import { GLOBAL_HEADER_MENU_ID, GLOBAL_SIDER_MENU_ID } from '@/constants/app';
import VerticalMixMenu from './modules/VerticalMixMenu';
import HorizontalMenu from './modules/HorizontalMenu';
import HorizontalMixMenu from './modules/HorizontalMixMenu';
import VerticalMenu from './modules/VerticalMenu';

interface Props {
mode: UnionKey.ThemeLayoutMode;
menus: MenuProps['items'];
childrenMenu: MenuProps['items'];
}

const headerContainer = document.getElementById(GLOBAL_HEADER_MENU_ID);

const siderContainer = document.getElementById(GLOBAL_SIDER_MENU_ID);

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

const componentsMap = {
vertical: createPortal(<VerticalMixMenu menus={menus} />, siderContainer),
'vertical-mix': <VerticalMixMenu menus={menus} />,
vertical: createPortal(<VerticalMenu menus={menus} />, siderContainer),
'vertical-mix': createPortal(<VerticalMixMenu menus={childrenMenu} />, siderContainer),
horizontal: createPortal(<HorizontalMenu />, headerContainer),
'horizontal-mix': <HorizontalMixMenu />
};
Expand Down
1 change: 1 addition & 0 deletions src/layouts/modules/global-menu/modules/HorizontalMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const HorizontalMenu = () => {
}

if (!headerContainer) return null;

return (
<AMenu
mode="horizontal"
Expand Down
2 changes: 2 additions & 0 deletions src/layouts/modules/global-menu/modules/HorizontalMixMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const HorizontalMixMenu = memo(() => {
}
}
if (!headerContainer || !siderContainer) return null;
console.log(siderContainer);

return (
<>
{createPortal(
Expand Down
126 changes: 126 additions & 0 deletions src/layouts/modules/global-menu/modules/VerticalMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { SimpleScrollbar } from '@sa/materials';
import type { Route, RouteRecordNormalized } from '@sa/simple-router';
import type { MenuInfo } from 'rc-menu/lib/interface';
import type { MenuProps } from 'antd';
import { getSiderCollapse } from '@/store/slice/app';
import { getThemeSettings } from '@/store/slice/theme';

interface LevelKeysProps {
key?: string;
children?: LevelKeysProps[];
}

interface Props {
menus: MenuProps['items'];
}

const getLevelKeys = (items1: LevelKeysProps[]) => {
const key: Record<string, number> = {};

if (!items1) return key;
const func = (items2: LevelKeysProps[], level = 1) => {
items2.forEach(item => {
if (item.key) {
key[item.key] = level;
}
if (item.children) {
func(item.children, level + 1);
}
});
};
func(items1);
return key;
};

function getSelectKey(route: Route) {
const { hideInMenu, activeMenu } = route.meta;

const name = route.name as string;

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

return [routeName];
}

const getSelectedMenuKeyPath = (matches: RouteRecordNormalized[]) => {
const result = matches.reduce((acc: string[], match, index) => {
if (index < matches.length - 1 && match.name) {
acc.push(match.name);
}
return acc;
}, []);

return result;
};

const VerticalMenu: FC<Props> = memo(({ menus }) => {
console.log(menus);

const route = useRoute();
const levelKeys = getLevelKeys(menus as LevelKeysProps[]);

const themeSettings = useAppSelector(getThemeSettings);

const selectedKeys = getSelectKey(route);

const router = useRouterPush();
const matches = route.matched;
const openKeys = () => {
return getSelectedMenuKeyPath(matches);
};

const inlineCollapsed = useAppSelector(getSiderCollapse);

const siderCollapse = themeSettings.layout.mode === 'vertical-mix' ? false : inlineCollapsed;

const [stateOpenKeys, setStateOpenKeys] = useState<string[]>(openKeys());

function handleClickMenu(menuInfo: MenuInfo) {
router.menuPush(menuInfo.key);
}

const onOpenChange: MenuProps['onOpenChange'] = keys => {
if (keys.includes('rc-menu-more')) {
setStateOpenKeys(keys);
return;
}

const currentOpenKey = keys.find(key => !stateOpenKeys.includes(key));

// open
if (currentOpenKey && themeSettings.isOnlyExpandCurrentParentMenu) {
const repeatIndex = keys
.filter(key => key !== currentOpenKey)
.findIndex(key => levelKeys[key] === levelKeys[currentOpenKey]);

setStateOpenKeys(
keys
// remove repeat key
.filter((_, index) => index !== repeatIndex)
// remove current level all child
.filter(key => levelKeys[key] <= levelKeys[currentOpenKey])
);
} else {
// close
setStateOpenKeys(keys);
}
};

return (
<SimpleScrollbar>
<AMenu
mode="inline"
items={menus}
inlineCollapsed={siderCollapse}
openKeys={stateOpenKeys}
onOpenChange={onOpenChange}
selectedKeys={selectedKeys}
onSelect={handleClickMenu}
className="size-full bg-container transition-300 border-0!"
inlineIndent={18}
/>
</SimpleScrollbar>
);
});

export default VerticalMenu;
Loading

0 comments on commit dab5333

Please sign in to comment.