"use client"; import { useState } from "react"; import NextImage from "next/image"; import { Bot, ClipboardList, ChevronDown, ChevronRight, Crop, FolderOpen, Frame, GitBranch, GitCompare, Image, ImageOff, Layers, LayoutPanelTop, MessageSquare, Package, Palette, Presentation, Repeat, Sparkles, Split, StickyNote, Type, Video, Wand2, type LucideIcon, } from "lucide-react"; import { CanvasUserMenu } from "@/components/canvas/canvas-user-menu"; import { useAuthQuery } from "@/hooks/use-auth-query"; import { api } from "@/convex/_generated/api"; import type { Id } from "@/convex/_generated/dataModel"; import { NODE_CATEGORY_META, NODE_CATEGORIES_ORDERED, catalogEntriesByCategory, isNodePaletteEnabled, type NodeCatalogEntry, } from "@/lib/canvas-node-catalog"; import { CANVAS_NODE_DND_MIME } from "@/lib/canvas-connection-policy"; import { cn } from "@/lib/utils"; const CATALOG_ICONS: Partial> = { image: Image, text: Type, prompt: Sparkles, color: Palette, video: Video, asset: Package, "ai-image": Sparkles, "ai-text": Type, "ai-video": Video, "agent-output": Bot, crop: Crop, "bg-remove": ImageOff, upscale: Wand2, "style-transfer": Wand2, "face-restore": Sparkles, curves: Sparkles, "color-adjust": Palette, "light-adjust": Sparkles, "detail-adjust": Wand2, render: Image, splitter: Split, loop: Repeat, agent: Bot, mixer: Layers, switch: GitBranch, group: FolderOpen, frame: Frame, note: StickyNote, "text-overlay": LayoutPanelTop, compare: GitCompare, comment: MessageSquare, presentation: Presentation, }; function SidebarRow({ entry, compact = false, }: { entry: NodeCatalogEntry; compact?: boolean; }) { const enabled = isNodePaletteEnabled(entry); const Icon = CATALOG_ICONS[entry.type] ?? ClipboardList; const onDragStart = (event: React.DragEvent) => { if (!enabled) return; event.dataTransfer.setData(CANVAS_NODE_DND_MIME, entry.type); event.dataTransfer.effectAllowed = "move"; }; const hint = entry.disabledHint ?? "Noch nicht verfügbar"; return (
{!compact ? {entry.label} : null} {!compact && entry.phase > 1 ? ( P{entry.phase} ) : null} {compact ? {entry.label} : null}
); } type CanvasSidebarProps = { canvasId: Id<"canvases">; railMode?: boolean; }; export default function CanvasSidebar({ canvasId, railMode = false, }: CanvasSidebarProps) { const canvas = useAuthQuery(api.canvases.get, { canvasId }); const byCategory = catalogEntriesByCategory(); const [collapsedByCategory, setCollapsedByCategory] = useState< Partial> >(() => Object.fromEntries( NODE_CATEGORIES_ORDERED.map((categoryId) => [categoryId, categoryId !== "source"]), ), ); const railEntries = NODE_CATEGORIES_ORDERED.flatMap( (categoryId) => byCategory.get(categoryId) ?? [], ); return ( ); }