// ======================================== // Sidebar Component // ======================================== // Collapsible navigation sidebar with 5-group accordion structure import { useCallback, useMemo } from 'react'; import { useIntl } from 'react-intl'; import { Home, FolderKanban, Workflow, AlertCircle, Sparkles, Terminal, Brain, Settings, HelpCircle, PanelLeftClose, PanelLeftOpen, LayoutDashboard, Clock, Zap, GitFork, Shield, History, Server, Layers, Wrench, Cog, } from 'lucide-react'; import { cn } from '@/lib/utils'; import { Button } from '@/components/ui/Button'; import { Accordion } from '@/components/ui/Accordion'; import { NavGroup, type NavItem } from '@/components/shared/NavGroup'; import { useAppStore } from '@/stores/appStore'; export interface SidebarProps { /** Whether sidebar is collapsed */ collapsed?: boolean; /** Callback when collapse state changes */ onCollapsedChange?: (collapsed: boolean) => void; /** Whether sidebar is open on mobile */ mobileOpen?: boolean; /** Callback to close mobile sidebar */ onMobileClose?: () => void; } // Navigation group definitions interface NavGroupDef { id: string; titleKey: string; icon?: React.ElementType; items: Array<{ path: string; labelKey: string; icon: React.ElementType; badge?: number | string; badgeVariant?: 'default' | 'success' | 'warning' | 'info'; }>; } // Define the 5 navigation groups with their items const navGroupDefinitions: NavGroupDef[] = [ { id: 'overview', titleKey: 'navigation.groups.overview', icon: Layers, items: [ { path: '/', labelKey: 'navigation.main.home', icon: Home }, { path: '/project', labelKey: 'navigation.main.project', icon: LayoutDashboard }, ], }, { id: 'workflow', titleKey: 'navigation.groups.workflow', icon: Workflow, items: [ { path: '/sessions', labelKey: 'navigation.main.sessions', icon: FolderKanban }, { path: '/lite-tasks', labelKey: 'navigation.main.liteTasks', icon: Zap }, { path: '/orchestrator', labelKey: 'navigation.main.orchestrator', icon: Workflow }, { path: '/coordinator', labelKey: 'navigation.main.coordinator', icon: GitFork }, { path: '/history', labelKey: 'navigation.main.history', icon: Clock }, { path: '/issues', labelKey: 'navigation.main.issues', icon: AlertCircle }, ], }, { id: 'knowledge', titleKey: 'navigation.groups.knowledge', icon: Brain, items: [ { path: '/memory', labelKey: 'navigation.main.memory', icon: Brain }, { path: '/prompts', labelKey: 'navigation.main.prompts', icon: History }, { path: '/skills', labelKey: 'navigation.main.skills', icon: Sparkles }, { path: '/commands', labelKey: 'navigation.main.commands', icon: Terminal }, { path: '/settings/rules', labelKey: 'navigation.main.rules', icon: Shield }, ], }, { id: 'tools', titleKey: 'navigation.groups.tools', icon: Wrench, items: [ { path: '/hooks', labelKey: 'navigation.main.hooks', icon: GitFork }, { path: '/settings/mcp', labelKey: 'navigation.main.mcp', icon: Server }, ], }, { id: 'configuration', titleKey: 'navigation.groups.configuration', icon: Cog, items: [ { path: '/settings/codexlens', labelKey: 'navigation.main.codexlens', icon: Sparkles }, { path: '/api-settings', labelKey: 'navigation.main.apiSettings', icon: Server }, { path: '/settings', labelKey: 'navigation.main.settings', icon: Settings }, { path: '/help', labelKey: 'navigation.main.help', icon: HelpCircle }, ], }, ]; export function Sidebar({ collapsed = false, onCollapsedChange, mobileOpen = false, onMobileClose, }: SidebarProps) { const { formatMessage } = useIntl(); const { sidebarCollapsed, expandedNavGroups, setExpandedNavGroups } = useAppStore(); const isCollapsed = onCollapsedChange ? collapsed : sidebarCollapsed; const handleToggleCollapse = useCallback(() => { if (onCollapsedChange) { onCollapsedChange(!collapsed); } else { useAppStore.getState().setSidebarCollapsed(!sidebarCollapsed); } }, [collapsed, sidebarCollapsed, onCollapsedChange]); const handleNavClick = useCallback(() => { // Close mobile sidebar when navigating if (onMobileClose) { onMobileClose(); } }, [onMobileClose]); const handleAccordionChange = useCallback((value: string[]) => { setExpandedNavGroups(value); }, [setExpandedNavGroups]); // Build nav groups with translated labels const navGroups = useMemo(() => { return navGroupDefinitions.map((group) => ({ ...group, items: group.items.map((item) => ({ ...item, label: formatMessage({ id: item.labelKey }), })) as NavItem[], })); }, [formatMessage]); return ( <> {/* Mobile overlay */} {mobileOpen && (