import { CaretDown, DotsThreeVertical } from "@phosphor-icons/react"; import { useEffect, useRef, useState, type MouseEvent, type ReactNode, } from "react"; import { cn } from "../../lib/cn"; import { IconButton } from "../actions/icon-button"; import { Menu, type MenuItem } from "../actions/menu"; import { useUhuruPanelState } from "../panel-context"; import { useUhuruPanelRoute } from "./panel-route-context"; export type UhuruPanelAction = Omit & { onClick: () => void; }; export type UhuruPanelItem = { action?: UhuruPanelAction[]; active?: boolean; badge?: ReactNode; children?: UhuruPanelItem[]; disabled?: boolean; element?: ReactNode; href?: string; icon?: ReactNode; id: string; label: ReactNode; onSelect?: () => void; path?: string; route?: boolean; }; export type UhuruPanelItemRenderContext = { active: boolean; collapsed: boolean; depth: number; expanded: boolean; hasChildren: boolean; }; export function filterPanelItems( items: UhuruPanelItem[], query: string, ): UhuruPanelItem[] { return items.flatMap((item) => { const itemMatches = String(item.label).toLowerCase().includes(query); const children = item.children ? filterPanelItems(item.children, query) : []; return itemMatches || children.length > 0 ? [{ ...item, children: children.length > 0 ? children : item.children }] : []; }); } export function flattenPanelItems(items: UhuruPanelItem[]): UhuruPanelItem[] { return items.flatMap((item) => [ item, ...(item.children ? flattenPanelItems(item.children) : []), ]); } export function panelIconMotionClassName( animation: "none" | "lift" | "slide" | "pulse", groupHover = true, ) { const hoverSelector = groupHover ? "group-hover:" : "hover:"; switch (animation) { case "lift": return `transition-transform duration-200 motion-reduce:transform-none ${hoverSelector}-translate-y-0.5`; case "slide": return `transition-transform duration-200 motion-reduce:transform-none ${hoverSelector}translate-x-0.5`; case "pulse": return `transition-transform duration-200 motion-reduce:transform-none ${hoverSelector}scale-105`; default: return ""; } } export function UhuruPanelItemView({ activeId, item, onItemSelect, renderItem, depth = 0, collapsed = false, }: { activeId?: string; collapsed?: boolean; depth?: number; item: UhuruPanelItem; onItemSelect?: (item: UhuruPanelItem) => void; renderItem?: ( item: UhuruPanelItem, context: UhuruPanelItemRenderContext, ) => ReactNode; }) { const panelRoute = useUhuruPanelRoute(); const active = item.active ?? (item.id === activeId || Boolean(item.path && panelRoute?.activeRoute?.path === item.path)); const [expanded, setExpanded] = useState(active); const hasChildren = Boolean(item.children?.length); const panelState = useUhuruPanelState(); const iconMotionClass = panelIconMotionClassName( panelState?.iconHoverAnimation ?? "none", ); function handleSelect( event: MouseEvent, ) { if (item.disabled) { event.preventDefault(); return; } if (item.route !== false && item.path && item.element) { event.preventDefault(); } onItemSelect?.(item); item.onSelect?.(); } const defaultContent = ( <> {depth === 0 ? ( {item.icon ?? ( )} ) : null} {item.label} {item.badge && !collapsed ? ( {item.badge} ) : null} {hasChildren && !collapsed ? (