/** * Effect Chain List - Manage effect chains and their order */ import { ChevronDown, ChevronRight, Copy, GripVertical, MoreVertical, Plus, Trash2 } from "lucide-react" import React, { useRef, useState } from "react" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Card } from "@/components/ui/card" import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Slider } from "@/components/ui/slider" import { Switch } from "@/components/ui/switch" import { EffectPipelineManager } from "../services/effect-pipeline-manager" import type { EffectChain } from "../types" interface EffectChainListProps { className?: string } export function EffectChainList({ className }: EffectChainListProps) { const [chains, setChains] = useState([]) const [expandedChains, setExpandedChains] = useState>(new Set()) const [draggedChain, setDraggedChain] = useState(null) const pipelineManager = useRef( new EffectPipelineManager("medium", { resolution: 1.0, effects: "all", fps: 30, antialiasing: true, }), ) const addNewChain = () => { const newChain: EffectChain = { id: `chain_${Date.now()}`, name: `Chain ${chains.length + 1}`, effects: [], enabled: true, order: chains.length, } setChains([...chains, newChain]) pipelineManager.current.addChain(newChain) setExpandedChains((prev) => new Set([...prev, newChain.id])) } const toggleChainExpanded = (chainId: string) => { setExpandedChains((prev) => { const newSet = new Set(prev) if (newSet.has(chainId)) { newSet.delete(chainId) } else { newSet.add(chainId) } return newSet }) } const toggleChainEnabled = (chainId: string) => { setChains((prev) => prev.map((chain) => (chain.id === chainId ? { ...chain, enabled: !chain.enabled } : chain))) } const toggleEffectEnabled = (chainId: string, effectId: string) => { setChains((prev) => prev.map((chain) => chain.id === chainId ? { ...chain, effects: chain.effects.map((effect) => effect.id === effectId ? { ...effect, enabled: !effect.enabled } : effect, ), } : chain, ), ) } const updateEffectIntensity = (chainId: string, effectId: string, intensity: number) => { setChains((prev) => prev.map((chain) => chain.id === chainId ? { ...chain, effects: chain.effects.map((effect) => (effect.id === effectId ? { ...effect, intensity } : effect)), } : chain, ), ) } const removeChain = (chainId: string) => { setChains((prev) => prev.filter((chain) => chain.id !== chainId)) pipelineManager.current.removeChain(chainId) setExpandedChains((prev) => { const newSet = new Set(prev) newSet.delete(chainId) return newSet }) } const duplicateChain = (chainId: string) => { const originalChain = chains.find((c) => c.id === chainId) if (!originalChain) return const newChain: EffectChain = { ...originalChain, id: `chain_${Date.now()}`, name: `${originalChain.name} Copy`, effects: originalChain.effects.map((effect) => ({ ...effect, id: `${effect.id}_copy_${Date.now()}`, })), } setChains((prev) => [...prev, newChain]) pipelineManager.current.addChain(newChain) } const handleDragStart = (chainId: string) => { setDraggedChain(chainId) } const handleDragOver = (e: React.DragEvent) => { e.preventDefault() } const handleDrop = (e: React.DragEvent, targetChainId: string) => { e.preventDefault() if (!draggedChain || draggedChain === targetChainId) return const draggedIndex = chains.findIndex((c) => c.id === draggedChain) const targetIndex = chains.findIndex((c) => c.id === targetChainId) if (draggedIndex === -1 || targetIndex === -1) return const newChains = [...chains] const [removed] = newChains.splice(draggedIndex, 1) newChains.splice(targetIndex, 0, removed) setChains(newChains) pipelineManager.current.setChainOrder(newChains.map((c) => c.id)) setDraggedChain(null) } const getEffectIcon = (effectType: string) => { const icons = { color_correction: "🎨", blur: "🌫️", vignette: "⚫", transform: "🔄", grain: "📺", chromatic_aberration: "🌈", lens_distortion: "👁️", } return icons[effectType as keyof typeof icons] || "⚡" } const getEffectName = (effectType: string) => { const names = { color_correction: "Color Correction", blur: "Blur", vignette: "Vignette", transform: "Transform", grain: "Film Grain", chromatic_aberration: "Chromatic Aberration", lens_distortion: "Lens Distortion", } return names[effectType as keyof typeof names] || effectType } return (

Effect Chains

{chains.length === 0 ? (

No effect chains yet

Add a chain to start applying effects

) : (
{chains.map((chain) => ( handleDragStart(chain.id)} onDragOver={handleDragOver} onDrop={(e) => handleDrop(e, chain.id)} > toggleChainExpanded(chain.id)}>
toggleChainEnabled(chain.id)} size="sm" /> {expandedChains.has(chain.id) ? ( ) : ( )} {chain.name} {chain.effects.length} effects duplicateChain(chain.id)}> Duplicate removeChain(chain.id)} className="text-destructive"> Delete
{chain.effects.length === 0 ? (
No effects in this chain
) : (
{chain.effects.map((effect) => (
toggleEffectEnabled(chain.id, effect.id)} size="sm" /> {getEffectIcon(effect.type)}
{getEffectName(effect.type)}
{Math.round((effect.intensity || 1) * 100)}% updateEffectIntensity(chain.id, effect.id, value / 100)} max={100} step={1} className="w-16" />
))}
)}
))}
)}
) }