/** * Node Palette Component * Categorized, searchable node palette for workflow editor */ "use client"; import { useState } from 'react'; import { Search } from 'lucide-react'; import * as Icons from 'lucide-react'; import { Input } from '@/components/ui/input'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { NODE_METADATA, NODE_CATEGORIES, type NodeType } from '@/types/workflow-nodes'; interface NodePaletteProps { onNodeSelect: (nodeType: NodeType) => void; } export function NodePalette({ onNodeSelect }: NodePaletteProps) { const [search, setSearch] = useState(''); // Filter nodes based on search const filterNodes = (nodeTypes: readonly string[]) => { if (!search) return nodeTypes; return nodeTypes.filter(type => { const metadata = NODE_METADATA[type as NodeType]; return ( metadata.label.toLowerCase().includes(search.toLowerCase()) || metadata.description.toLowerCase().includes(search.toLowerCase()) ); }); }; return (
{/* Search */}
setSearch(e.target.value)} className="pl-9" />
{/* Categorized Tabs */} Triggers Actions Social Logic AI {/* Triggers */} {filterNodes(NODE_CATEGORIES.TRIGGERS).map(type => ( onNodeSelect(type as NodeType)} /> ))} {/* Actions */} {filterNodes(NODE_CATEGORIES.ACTIONS).map(type => ( onNodeSelect(type as NodeType)} /> ))} {/* Social */} {filterNodes(NODE_CATEGORIES.SOCIAL).map(type => ( onNodeSelect(type as NodeType)} /> ))} {/* Logic */} {filterNodes(NODE_CATEGORIES.LOGIC).map(type => ( onNodeSelect(type as NodeType)} /> ))} {/* AI */} {filterNodes(NODE_CATEGORIES.AI).map(type => ( onNodeSelect(type as NodeType)} /> ))}
); } function NodeCard({ nodeType, onClick }: { nodeType: NodeType; onClick: () => void }) { const metadata = NODE_METADATA[nodeType]; const Icon = Icons[metadata.icon as keyof typeof Icons] as React.ComponentType<{ className?: string }>; return ( ); }