import { type MouseEvent, type ReactNode, useEffect, useMemo, useState } from "react"; import clsx from "clsx"; import { ChevronDown } from "lucide-react"; export interface SidebarItem { label: string; href: string; icon?: ReactNode; children?: SidebarItem[]; } export interface SidebarProps { title?: string; items: SidebarItem[]; activeHref?: string; onNavigate?: (href: string) => void; headerExtra?: ReactNode; } /** * Brand palette * #10B981 — dominant dark green → brand mark, active state, hover text * #10B981 — secondary green → hover background tint * #10B981 — muted green tone → sidebar canvas */ const Sidebar = ({ title, items, activeHref, onNavigate, headerExtra, }: SidebarProps) => { const activePath = activeHref?.toLowerCase() ?? ""; const defaultExpanded = useMemo( () => items.reduce>((acc, item) => { if (item.children?.length) { acc[item.href] = activePath === item.href.toLowerCase() || activePath.startsWith(`${item.href.toLowerCase()}/`) || item.children.some((child) => activePath.startsWith(child.href.toLowerCase()), ); } return acc; }, {}), [activePath, items], ); const [expanded, setExpanded] = useState>(defaultExpanded); useEffect(() => { setExpanded((current) => ({ ...defaultExpanded, ...current })); }, [defaultExpanded]); const navigateTo = (event: MouseEvent, href: string) => { if (onNavigate) { event.preventDefault(); onNavigate(href); } }; return ( ); }; export default Sidebar;