'use client' import type { AnyNodeId, Collection, CollectionId } from '@pascal-app/core' import { useScene } from '@pascal-app/core' import { Check, ChevronDown, ChevronRight, Layers, MoreHorizontal, Pencil, Plus, Trash2, X } from 'lucide-react' import { useState } from 'react' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/primitives/dropdown-menu' import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/primitives/popover' import { ColorDot } from '@/components/ui/primitives/color-dot' import { cn } from '@/lib/utils' interface CollectionsPopoverProps { nodeId: AnyNodeId collectionIds?: CollectionId[] children: React.ReactNode } export function CollectionsPopover({ nodeId, collectionIds, children }: CollectionsPopoverProps) { const collections = useScene((s) => s.collections) const nodes = useScene((s) => s.nodes) const createCollection = useScene((s) => s.createCollection) const deleteCollection = useScene((s) => s.deleteCollection) const updateCollection = useScene((s) => s.updateCollection) const addToCollection = useScene((s) => s.addToCollection) const removeFromCollection = useScene((s) => s.removeFromCollection) const [open, setOpen] = useState(false) const [showCreateInput, setShowCreateInput] = useState(false) const [createName, setCreateName] = useState('') const [renamingId, setRenamingId] = useState(null) const [renameValue, setRenameValue] = useState('') const [renameColor, setRenameColor] = useState('') const [deletingId, setDeletingId] = useState(null) const [expandedIds, setExpandedIds] = useState>(new Set()) const memberIds = collectionIds ?? [] const allCollections = Object.values(collections) const handleCreate = () => { if (!createName.trim()) return createCollection(createName.trim(), [nodeId]) setCreateName('') setShowCreateInput(false) } const handleRenameConfirm = (id: CollectionId) => { if (!renameValue.trim()) return updateCollection(id, { name: renameValue.trim(), color: renameColor || undefined }) setRenamingId(null) } const toggleMembership = (collectionId: CollectionId) => { if (memberIds.includes(collectionId)) { removeFromCollection(collectionId, nodeId) } else { addToCollection(collectionId, nodeId) } } const toggleExpand = (collectionId: CollectionId) => { setExpandedIds((prev) => { const next = new Set(prev) if (next.has(collectionId)) next.delete(collectionId) else next.add(collectionId) return next }) } return ( {children} {/* Header */}
Collections
{/* Create input */} {showCreateInput && (
setCreateName(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') handleCreate() if (e.key === 'Escape') { setShowCreateInput(false); setCreateName('') } }} placeholder="Collection name…" className="flex-1 min-w-0 rounded-md border border-border/50 bg-background/50 px-2 py-1 text-xs text-foreground placeholder:text-muted-foreground/60 outline-none focus:border-ring focus:ring-1 focus:ring-ring/30" />
)} {/* Collections list */}
{allCollections.length === 0 ? (

No collections yet. Create one to group items together.

) : (
    {allCollections.map((collection) => { const isIn = memberIds.includes(collection.id) const isExpanded = expandedIds.has(collection.id) const isRenaming = renamingId === collection.id const isDeleting = deletingId === collection.id if (isDeleting) { return (
  • Delete "{collection.name}"?
  • ) } if (isRenaming) { return (
  • setRenameValue(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') handleRenameConfirm(collection.id) if (e.key === 'Escape') setRenamingId(null) }} className="flex-1 min-w-0 rounded-md border border-border/50 bg-background/50 px-2 py-1 text-xs text-foreground outline-none focus:border-ring focus:ring-1 focus:ring-ring/30" />
  • ) } return (
  • {/* Color dot — click to pick color */} updateCollection(collection.id, { color: c })} /> {/* Name + count — clicking toggles membership */} {/* Membership check */}
    {isIn && }
    {/* Expand toggle (only if has members) */} {collection.nodeIds.length > 0 && ( )} {/* More dropdown */} { setRenamingId(collection.id); setRenameValue(collection.name); setRenameColor(collection.color ?? '') }}> Rename setDeletingId(collection.id)}> Delete
    {/* Expanded member list */} {isExpanded && (
      {collection.nodeIds.map((nid) => { const n = nodes[nid] return (
    • {n?.name ?? nid}
    • ) })}
    )}
  • ) })}
)}
) }