"use client"; import { useState, useCallback } from "react"; export type TreeNode = { name: string; path: string; type: "object" | "document" | "folder" | "file" | "database" | "report"; icon?: string; defaultView?: "table" | "kanban"; children?: TreeNode[]; }; // --- Icons (inline SVG for zero-dep) --- function FolderIcon({ open }: { open?: boolean }) { return open ? ( ) : ( ); } function TableIcon() { return ( ); } function KanbanIcon() { return ( ); } function DocumentIcon() { return ( ); } function FileIcon() { return ( ); } function DatabaseIcon() { return ( ); } function ReportIcon() { return ( ); } function ChevronIcon({ open }: { open: boolean }) { return ( ); } // --- Node Icon Resolver --- function NodeIcon({ node, open }: { node: TreeNode; open?: boolean }) { switch (node.type) { case "object": return node.defaultView === "kanban" ? : ; case "document": return ; case "folder": return ; case "database": return ; case "report": return ; default: return ; } } // --- Tree Node Component --- function TreeNodeItem({ node, depth, activePath, onSelect, expandedPaths, onToggleExpand, }: { node: TreeNode; depth: number; activePath: string | null; onSelect: (node: TreeNode) => void; expandedPaths: Set; onToggleExpand: (path: string) => void; }) { const hasChildren = node.children && node.children.length > 0; const isExpandable = hasChildren || node.type === "folder" || node.type === "object"; const isExpanded = expandedPaths.has(node.path); const isActive = activePath === node.path; const handleClick = () => { onSelect(node); if (isExpandable) { onToggleExpand(node.path); } }; const typeColor = node.type === "object" ? "var(--color-accent)" : node.type === "document" ? "#60a5fa" : node.type === "database" ? "#c084fc" : node.type === "report" ? "#22c55e" : "var(--color-text-muted)"; return (
{/* Children */} {isExpanded && hasChildren && (
0 ? "1px solid var(--color-border)" : "none", marginLeft: `${depth * 16 + 16}px`, }} > {node.children!.map((child) => ( ))}
)}
); } // --- Exported Tree Component --- export function KnowledgeTree({ tree, activePath, onSelect, }: { tree: TreeNode[]; activePath: string | null; onSelect: (node: TreeNode) => void; }) { const [expandedPaths, setExpandedPaths] = useState>( () => new Set(), ); const handleToggleExpand = useCallback((path: string) => { setExpandedPaths((prev) => { const next = new Set(prev); if (next.has(path)) {next.delete(path);} else {next.add(path);} return next; }); }, []); if (tree.length === 0) { return (
No files in workspace
); } return (
{tree.map((node) => ( ))}
); }