import React, { useContext } from 'react' import { Menu, Drawer } from 'antd' import { MenuConfig, renderMenuHelper } from './renderMenu' import { themePropsCtx } from '../ctx' import s from './index.module.less' import type { ThemeContextValue } from '..' import { LayoutContext } from './ctx' import { analyzePageInfo } from '../analyzeStaticData' import { getStaticDataValue } from '../utils' interface Props { sideNavsData: readonly MenuConfig[] | null | undefined } const renderMenu = renderMenuHelper(false) const AppSider: React.FC> = ({ sideNavsData, }) => { const themeProps = useContext(themePropsCtx) const subMenuKeys: string[] = [] const menuItems = sideNavsData ? renderMenu(sideNavsData, true, subMenuKeys) : [] const layoutCtxVal = useContext(LayoutContext) const isSmallScreen = !layoutCtxVal.screenWidth?.md return (
{sideNavsData && ( <> )} {isSmallScreen && ( { layoutCtxVal.setIsSlideSiderOpen(false) }} rootStyle={{ top: 64, height: 'calc(100vh - 64px)', }} bodyStyle={{ padding: '12px 0px', }} getContainer=".vp-local-layout" width={280} > )}
) } export default AppSider export interface DefaultSideNavsOpts { groupConfig: { [groupKey: string]: { [subGroupKey: string]: { label?: string order?: number } } } /** * force defaultSideNavs to treat it as curent page group. * for example, user can use this to * force side nav to display a group during 404 state */ forceGroup?: string } export function defaultSideNavs( { loadState, staticData, themeConfig, pageGroups }: ThemeContextValue, opts?: DefaultSideNavsOpts ): MenuConfig[] | null { const { i18n } = themeConfig || {} const currentPageInfo = analyzePageInfo( loadState.routePath, staticData[loadState.routePath], i18n ) // console.log('defaultSideNavs', currentPageInfo, groups) // groupKey of the current page const groupKey = (() => { if (opts?.forceGroup) return opts.forceGroup // infer the group of the current page. // currentPageInfo.group may be wrong because: // if there is also pages like /guide/start , // then /guide should not be grouped with /faq . // instead, /guide should be moved to the "guide" group if ( currentPageInfo.group === '/' && pageGroups[currentPageInfo.pageKeyInGroup] ) { return currentPageInfo.pageKeyInGroup } return currentPageInfo.group })() const subGroups = pageGroups[groupKey] ?? {} const result: MenuConfig[] = [] Object.entries(subGroups) // remove pages with different locale .map(([subGroupKey, pages]) => { const filtered = pages.filter( ({ pageLocaleKey }) => currentPageInfo.localeKey === pageLocaleKey ) return [subGroupKey, filtered] as const }) // if all pages of a subGroup are filtered out, drop it .filter(([subGroupKey, pages]) => pages.length > 0) // sort subGroup .sort(([subGroupKeyA], [subGroupKeyB]) => { // pages with '/' subGroup are put afront if (subGroupKeyA === '/') return -1 if (subGroupKeyB === '/') return 1 const orderA = getGroupConfig(groupKey, subGroupKeyA)?.order ?? 1 const orderB = getGroupConfig(groupKey, subGroupKeyB)?.order ?? 1 if (orderA !== orderB) return orderA - orderB return subGroupKeyA.localeCompare(subGroupKeyB) }) .map(([subGroupKey, pages]) => { if (subGroupKey === '/') { pages .sort((pageA, pageB) => sortPages( pageA.pageStaticData, pageB.pageStaticData, pageA.pagePath, pageB.pagePath ) ) // pages with path params should not be showed in sideNav .filter((page) => !page.pagePath.includes('/:')) .forEach((page) => { result.push({ label: page.pageTitle, path: page.pagePath, }) }) return } const subGroupLabel = getGroupConfig(groupKey, subGroupKey)?.label ?? subGroupKey const subGroupItems = pages .sort((pageA, pageB) => sortPages( pageA.pageStaticData, pageB.pageStaticData, pageA.pagePath, pageB.pagePath ) ) // pages with path params should not be showed in sideNav .filter((page) => !page.pagePath.includes('/:')) .map((page) => { return { label: page.pageTitle, path: page.pagePath, } }) if (subGroupItems.length > 0) result.push({ group: subGroupLabel, children: subGroupItems, }) }) return result function getGroupConfig(groupKey: string, subGroupKey: string) { return opts?.groupConfig?.[groupKey]?.[subGroupKey] } } function sortPages( pageStaticDataA: any, pageStaticDataB: any, pathA: string, pathB: string ) { const orderA = Number(getStaticDataValue(pageStaticDataA, 'order') ?? 1) const orderB = Number(getStaticDataValue(pageStaticDataB, 'order') ?? 1) if (!Number.isNaN(orderA) && !Number.isNaN(orderB) && orderA !== orderB) return orderA - orderB return pathA.localeCompare(pathB) }