import * as React from 'react'; import RouterLink from 'next/link'; import { usePathname } from 'next/navigation'; import Box from '@mui/material/Box'; import Chip from '@mui/material/Chip'; import Drawer from '@mui/material/Drawer'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; import { ArrowSquareOut as ArrowSquareOutIcon } from '@phosphor-icons/react/dist/ssr/ArrowSquareOut'; import { CaretDown as CaretDownIcon } from '@phosphor-icons/react/dist/ssr/CaretDown'; import { CaretRight as CaretRightIcon } from '@phosphor-icons/react/dist/ssr/CaretRight'; import type { NavItemConfig } from '@/types/nav'; import { paths } from '@/paths'; import { isNavItemActive } from '@/lib/is-nav-item-active'; import { Logo } from '@/components/core/logo'; import { icons } from './nav-icons'; import { WorkspacesSwitch } from './workspaces-switch'; export interface MobileNavProps { onClose?: () => void; open?: boolean; items?: NavItemConfig[]; } export function MobileNav({ items = [], open, onClose }: MobileNavProps): React.JSX.Element { const pathname = usePathname(); return ( {renderNavGroups({ items, onClose, pathname })} ); } function renderNavGroups({ items, onClose, pathname, }: { items: NavItemConfig[]; onClose?: () => void; pathname: string; }): React.JSX.Element { const children = items.reduce((acc: React.ReactNode[], curr: NavItemConfig): React.ReactNode[] => { acc.push( {curr.title ? ( {curr.title} ) : null} {renderNavItems({ depth: 0, items: curr.items, onClose, pathname })} ); return acc; }, []); return ( {children} ); } function renderNavItems({ depth = 0, items = [], onClose, pathname, }: { depth: number; items?: NavItemConfig[]; onClose?: () => void; pathname: string; }): React.JSX.Element { const children = items.reduce((acc: React.ReactNode[], curr: NavItemConfig): React.ReactNode[] => { const { items: childItems, key, ...item } = curr; const forceOpen = childItems ? Boolean(childItems.find((childItem) => childItem.href && pathname.startsWith(childItem.href))) : false; acc.push( {childItems ? renderNavItems({ depth: depth + 1, items: childItems, onClose, pathname }) : null} ); return acc; }, []); return ( {children} ); } interface NavItemProps extends Omit { children?: React.ReactNode; depth: number; forceOpen?: boolean; onClose?: () => void; pathname: string; } function NavItem({ children, depth, disabled, external, forceOpen = false, href, icon, label, matcher, onClose, pathname, title, }: NavItemProps): React.JSX.Element { const [open, setOpen] = React.useState(forceOpen); const active = isNavItemActive({ disabled, external, href, matcher, pathname }); const Icon = icon ? icons[icon] : null; const ExpandIcon = open ? CaretDownIcon : CaretRightIcon; const isBranch = children && !href; const showChildren = Boolean(children && open); return ( { setOpen(!open); }, onKeyUp: (event: React.KeyboardEvent): void => { if (event.key === 'Enter' || event.key === ' ') { setOpen(!open); } }, role: 'button', } : { ...(href ? { component: external ? 'a' : RouterLink, href, target: external ? '_blank' : undefined, rel: external ? 'noreferrer' : undefined, onClick: (): void => { onClose?.(); }, } : { role: 'button' }), })} sx={{ alignItems: 'center', borderRadius: 1, color: 'var(--NavItem-color)', cursor: 'pointer', display: 'flex', flex: '0 0 auto', gap: 1, p: '6px 16px', position: 'relative', textDecoration: 'none', whiteSpace: 'nowrap', ...(disabled && { bgcolor: 'var(--NavItem-disabled-background)', color: 'var(--NavItem-disabled-color)', cursor: 'not-allowed', }), ...(active && { bgcolor: 'var(--NavItem-active-background)', color: 'var(--NavItem-active-color)', ...(depth > 0 && { '&::before': { bgcolor: 'var(--NavItem-children-indicator)', borderRadius: '2px', content: '" "', height: '20px', left: '-14px', position: 'absolute', width: '3px', }, }), }), ...(open && { color: 'var(--NavItem-open-color)' }), '&:hover': { ...(!disabled && !active && { bgcolor: 'var(--NavItem-hover-background)', color: 'var(--NavItem-hover-color)' }), }, }} tabIndex={0} > {Icon ? ( ) : null} {title} {label ? : null} {external ? ( ) : null} {isBranch ? ( ) : null} {showChildren ? ( {children} ) : null} ); }