/** * Plan viewer component for Smart Montage Planner * Displays the generated montage plan with sequences and timeline visualization */ import { Check, Layers, Sparkles, TrendingUp, Wand2, X } from "lucide-react" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Progress } from "@/components/ui/progress" import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area" import { Separator } from "@/components/ui/separator" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { useMediaFiles } from "@/features/app-state/hooks/use-media-files" import type { MediaFile } from "@/features/media/types/media" import { formatTime } from "@/lib/date" import type { MediaItem } from "@/types/generated/tauri-bindings" import { usePlanGenerator } from "../../hooks/use-plan-generator" import { useTimelineIntegration } from "../../hooks/use-timeline-integration" import type { MontagePlan, SequenceType } from "../../types" interface PlanViewerProps { plan: MontagePlan } export function PlanViewer({ plan }: PlanViewerProps) { const { planStats, sequenceBreakdown, emotionalArc, transitionUsage } = usePlanGenerator() const { mediaFiles } = useMediaFiles() const { applyPlanToTimeline, isApplying, error, canApplyPlan } = useTimelineIntegration() // TODO: Implement plan validation const planValidation = null as any const handleApplyToTimeline = async () => { // Convert MediaItem[] to MediaFile[] const convertedMediaFiles: MediaFile[] = mediaFiles.map((item: MediaItem) => ({ id: item.id, path: item.path, name: item.name, isVideo: item.media_type === "Video", isAudio: item.media_type === "Audio", duration: item.duration || 0, format: item.metadata?.format || "", codec: item.metadata?.codec || "", width: item.metadata?.resolution?.width || 0, height: item.metadata?.resolution?.height || 0, frameRate: item.metadata?.frame_rate || 0, bitrate: item.metadata?.bitrate || 0, })) await applyPlanToTimeline(plan, convertedMediaFiles, { createNewSection: true, sectionName: plan.name, applyTransitions: true, }) } const getSequenceColor = (type: SequenceType) => { const colors = { intro: "bg-blue-500", main: "bg-green-500", climax: "bg-red-500", resolution: "bg-purple-500", outro: "bg-indigo-500", montage: "bg-yellow-500", } return colors[type] || "bg-gray-500" } const getScoreColor = (score: number) => { if (score >= 80) return "text-green-600" if (score >= 60) return "text-yellow-600" return "text-red-600" } return (
{sequence.clips.length} clips
Energy: {sequence.energyLevel}%
Pacing Type
{plan.pacing.type.replace("-", " ")}
Average Cut Duration
{plan.pacing.averageCutDuration.toFixed(1)}s
Cut Range
{plan.pacing.cutDurationRange[0].toFixed(1)}s - {plan.pacing.cutDurationRange[1].toFixed(1)}s
Rhythm Complexity
{plan.pacing.rhythmComplexity}%
No transitions applied yet
)}{issue.message}
Suggestions
{planValidation.suggestions.map((suggestion: any, index: number) => (• {suggestion}
))}Run validation to check plan quality
)}