"use client"; import { ChevronDownIcon } from "lucide-react"; import { AnimatePresence, motion, useReducedMotion } from "motion/react"; import { useId, useState } from "react"; import { cn } from "@/lib/utils"; export interface LaunchTask { id: string; label: string; hint?: string; done?: boolean; } export interface LaunchGroup { id: string; title: string; tasks: LaunchTask[]; } export interface LaunchListProps { title?: string; description?: string; groups: LaunchGroup[]; defaultOpen?: string[]; onToggleTask?: (taskId: string, done: boolean) => void; className?: string; } const spring = { type: "spring", stiffness: 380, damping: 32 } as const; function Ring({ value, total }: { value: number; total: number }) { const reduce = useReducedMotion(); const r = 15; const c = 2 * Math.PI * r; const pct = total ? value / total : 0; return (
{Math.round(pct * 100)}%
); } function TaskCheck({ done }: { done: boolean }) { const reduce = useReducedMotion(); return ( ); } export function LaunchList({ title = "Get set up", description, groups: initial, defaultOpen, onToggleTask, className, }: LaunchListProps) { const reduce = useReducedMotion(); const baseId = useId(); const [groups, setGroups] = useState(initial); const [open, setOpen] = useState( () => defaultOpen ?? [initial.find((g) => g.tasks.some((t) => !t.done))?.id ?? initial[0]?.id].filter(Boolean), ); const all = groups.flatMap((g) => g.tasks); const done = all.filter((t) => t.done).length; const toggle = (taskId: string) => { const next = !all.find((t) => t.id === taskId)?.done; setGroups((gs) => gs.map((g) => ({ ...g, tasks: g.tasks.map((t) => (t.id === taskId ? { ...t, done: next } : t)) })), ); onToggleTask?.(taskId, next); }; return (

{title}

{description ?? ( <> {done} of {all.length} {" "} done{done === all.length ? " – nice work" : ""} )}

{groups.map((g) => { const isOpen = open.includes(g.id); const gDone = g.tasks.filter((t) => t.done).length; const complete = gDone === g.tasks.length; const panelId = `${baseId}-${g.id}`; return (
{isOpen && (
    {g.tasks.map((t) => (
  • ))}
)}
); })}
); }