import { MenuFoldOutlined } from '@ant-design/icons'; import { css } from '@emotion/react'; import type { MenuProps } from 'antd'; import { Menu } from 'antd'; import { Link, useLocale, useLocation, useNavData, useSiteData } from 'dumi'; import { INavItem } from 'dumi/dist/client/theme-api/types'; import { useCallback } from 'react'; import useAdditionalThemeConfig from '../../hooks/useAdditionalThemeConfig'; import useLocaleValue from '../../hooks/useLocaleValue'; import useSiteToken from '../../hooks/useSiteToken'; import { getTargetLocalePath, isExternalLinks } from '../../utils'; import { type IResponsive } from './index'; import { getMoreLinksGroup } from './More'; export interface NavigationProps { isMobile: boolean; responsive: IResponsive; } const useStyle = () => { const { token } = useSiteToken(); const { antCls, iconCls, fontFamily, headerHeight, menuItemBorder, colorPrimary } = token; return { nav: css` height: 100%; font-size: 14px; font-family: Avenir, ${fontFamily}, sans-serif; border: 0; &${antCls}-menu-horizontal { border-bottom: none; & > ${antCls}-menu-item, & > ${antCls}-menu-submenu { min-width: (40px + 12px * 2); height: ${headerHeight}px; padding-right: 12px; padding-left: 12px; line-height: ${headerHeight}px; &::after { top: 0; right: 12px; bottom: auto; left: 12px; border-width: ${menuItemBorder}px; } } & ${antCls}-menu-submenu-title ${iconCls} { margin: 0; } & > ${antCls}-menu-item-selected { a { color: ${colorPrimary}; } } } & > ${antCls}-menu-item, & > ${antCls}-menu-submenu { text-align: center; } `, popoverMenuNav: css` ${antCls}-menu-item, ${antCls}-menu-submenu { text-align: left; } ${antCls}-menu-item-group-title { padding-left: 24px; } ${antCls}-menu-item-group-list { padding: 0 16px; } ${antCls}-menu-item, a { color: #333; } ` }; }; export default function Navigation({ isMobile, responsive }: NavigationProps) { const { pathname, search } = useLocation(); const { locales } = useSiteData(); const { github, socialLinks } = useAdditionalThemeConfig(); // 统一使用 themeConfig.nav,使用 useNavData,当存在自定义 pages 时,会导致 nav 混乱 const navList = useNavData(); const locale = useLocale(); const moreLinks = useLocaleValue('moreLinks'); const activeMenuItem = pathname.split('/').slice(0, 2).join('/'); const createMenuItems = (navs: INavItem[]) => { return navs.map((navItem: INavItem) => { const linkKeyValue = (navItem.link ?? '').split('/').slice(0, 2).join('/'); return { // eslint-disable-next-line no-nested-ternary label: navItem.children ? ( navItem.title ) : isExternalLinks(navItem.link) ? ( {navItem.title} ) : ( {navItem.title} ), key: isExternalLinks(navItem.link) ? navItem.link : linkKeyValue, children: navItem.children ? createMenuItems(navItem.children) : null }; }); }; const menuItems: MenuProps['items'] = createMenuItems(navList); // 获取小屏幕下多语言导航栏节点 const getLangNode = useCallback(() => { if (locales.length < 2) { return null; } if (locales.length === 2) { const nextLang = locales.filter((item) => item.id !== locale.id)[0]; const nextPath = getTargetLocalePath({ current: locale, target: nextLang }); return { label: ( {nextLang.name} ), key: nextLang.id }; } return { label: {locale.name}, key: 'multi-lang', children: locales .filter((item) => item.id !== locale.id) .map((item) => { const nextPath = getTargetLocalePath({ current: locale, target: item }); return { label: ( {item.name} ), key: item.id }; }) }; }, [locale, locales]); let additional: MenuProps['items']; const additionalItems: MenuProps['items'] = [ github || socialLinks?.github ? { label: ( GitHub ), key: 'github' } : null, getLangNode(), ...(getMoreLinksGroup(moreLinks) || []) ]; if (isMobile) { additional = additionalItems; } else if (responsive === 'crowded') { additional = [ { label: , key: 'additional', children: [...additionalItems] } ]; } const items: MenuProps['items'] = [...(menuItems ?? []), ...(additional ?? [])]; const menuMode = isMobile ? 'inline' : 'horizontal'; const style = useStyle(); return ( ); }