import { AppShell, Badge, NavLink, ScrollArea, Stack, Text, Tooltip, UnstyledButton, rem, } from '@mantine/core'; import { IconChevronLeft, IconChevronRight, } from '@tabler/icons-react'; import type { Icon } from '@tabler/icons-react'; import { useTranslation } from 'react-i18next'; import { BrandMark } from '@ema-platform/auth'; export interface NavItem { label: string; icon: Icon; to?: string; /** Not yet connected to real data — surfaced as a "Soon" badge. */ soon?: boolean; } /** A labelled group of nav items. */ export interface NavSection { /** i18n key or literal heading. Omit for an ungrouped leading block. */ label?: string; items: NavItem[]; } /** Both shapes are accepted so callers can migrate to sections gradually. */ export type NavEntries = NavItem[] | NavSection[]; function toSections(entries: NavEntries): NavSection[] { if (entries.length === 0) return []; const isSectioned = (entries as NavSection[])[0]?.items !== undefined; return isSectioned ? (entries as NavSection[]) : [{ items: entries as NavItem[] }]; } interface AppSidebarProps { navItems: NavEntries; collapsed: boolean; activePath: string; onToggleCollapse: () => void; onNavigate: (item: NavItem) => void; brandName: string; brandSubtitle: string; } export function AppSidebar({ navItems, collapsed, activePath, onToggleCollapse, onNavigate, brandName, brandSubtitle, }: AppSidebarProps) { const { t } = useTranslation(); const activeNavItem = (item: NavItem) => !!item.to && (activePath === item.to || activePath.startsWith(`${item.to}/`)); return ( <> {/* Brand header */}