{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "card-progress-tailwind",
  "type": "registry:item",
  "title": "Progress Card (Tailwind)",
  "description": "A file upload progress card with multiple file tracking.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "https://roiui.com/r/button-tailwind.json",
    "https://roiui.com/r/card-tailwind.json",
    "https://roiui.com/r/progress-tailwind.json"
  ],
  "files": [
    {
      "path": "registry/brook/tailwind/blocks/card-progress/components/progress-card.tsx",
      "content": "\"use client\";\n\nimport { AlertCircle, Check } from \"lucide-react\";\nimport { Card, CardContent } from \"@/registry/brook/tailwind/ui/card\";\n\nexport type StepStatus = \"pending\" | \"in_progress\" | \"complete\" | \"error\" | \"warning\";\n\nexport type Step = {\n  id: string;\n  title: string;\n  description?: string;\n  status: StepStatus;\n};\n\ntype StepIndicatorProps = {\n  status: StepStatus;\n  isFinal?: boolean;\n};\n\nfunction AnimatedClock({ className }: { className?: string }) {\n  return (\n    <svg\n      className={className}\n      fill=\"none\"\n      height=\"12\"\n      stroke=\"currentColor\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      strokeWidth=\"2.5\"\n      viewBox=\"0 0 24 24\"\n      width=\"12\"\n    >\n      <circle cx=\"12\" cy=\"12\" r=\"10\" />\n      <line x1=\"12\" x2=\"12\" y1=\"12\" y2=\"7\" />\n      <line\n        className=\"animate-[spin_2s_linear_infinite] motion-reduce:animate-none\"\n        style={{ transformOrigin: \"12px 12px\" }}\n        x1=\"12\"\n        x2=\"15\"\n        y1=\"12\"\n        y2=\"13\"\n      />\n    </svg>\n  );\n}\n\nconst BASE_CLASSES = \"relative z-[1] flex h-5 w-5 items-center justify-center rounded-full\";\n\nfunction getIndicatorConfig(status: StepStatus, isFinal: boolean) {\n  switch (status) {\n    case \"complete\":\n      return {\n        className: `${BASE_CLASSES} animate-[circle-reveal_0.2s_cubic-bezier(0.165,0.84,0.44,1)_forwards] motion-reduce:animate-none ${\n          isFinal ? \"bg-[var(--success)]\" : \"bg-[var(--foreground)]\"\n        }`,\n        icon: \"check\",\n        iconClassName:\n          \"opacity-0 animate-[icon-pop_0.15s_cubic-bezier(0.165,0.84,0.44,1)_0.05s_forwards] motion-reduce:animate-none motion-reduce:opacity-100 text-[var(--background)]\",\n      } as const;\n    case \"in_progress\":\n      return {\n        className: `${BASE_CLASSES} border-2 border-[var(--border)] bg-[var(--card)]`,\n        icon: null,\n        iconClassName: null,\n      } as const;\n    case \"error\":\n      return {\n        className: `${BASE_CLASSES} bg-[var(--destructive)]`,\n        icon: \"error\",\n        iconClassName: \"text-[var(--destructive-foreground)]\",\n      } as const;\n    case \"warning\":\n      return {\n        className: `${BASE_CLASSES} bg-[var(--warning)]`,\n        icon: \"clock\",\n        iconClassName: \"text-[var(--warning-foreground)]\",\n      } as const;\n    default:\n      return {\n        className: `${BASE_CLASSES} border-2 border-[var(--border)] bg-[var(--card)]`,\n        icon: null,\n        iconClassName: null,\n      } as const;\n  }\n}\n\nfunction StepIndicator({ status, isFinal = false }: StepIndicatorProps) {\n  const { className, icon, iconClassName } = getIndicatorConfig(status, isFinal);\n  const showSpinner = status === \"in_progress\" || status === \"complete\";\n  const isComplete = status === \"complete\";\n\n  return (\n    <div className=\"relative h-5 w-5\">\n      {showSpinner && (\n        <div\n          className={`absolute inset-0 z-[2] h-5 w-5 animate-spin rounded-full border-2 border-[var(--border)] border-t-[var(--foreground)] bg-[var(--card)] transition-opacity duration-300 ease-out will-change-transform motion-reduce:animate-none ${\n            isComplete ? \"opacity-0\" : \"opacity-100\"\n          }`}\n        />\n      )}\n      <div className={className}>\n        {icon === \"clock\" && <AnimatedClock className={iconClassName!} />}\n        {icon === \"check\" && <Check className={iconClassName!} size={14} strokeWidth={3} />}\n        {icon === \"error\" && <AlertCircle className={iconClassName!} size={14} strokeWidth={2.5} />}\n      </div>\n    </div>\n  );\n}\n\nfunction getTitleClassName(status: StepStatus) {\n  switch (status) {\n    case \"error\":\n      return \"text-[var(--destructive)]\";\n    case \"warning\":\n      return \"text-[var(--warning)]\";\n    case \"complete\":\n      return \"text-[oklch(from_var(--foreground)_l_c_h_/_0.5)]\";\n    default:\n      return \"text-[var(--muted-foreground)]\";\n  }\n}\n\ntype ProgressCardProps = {\n  steps: Step[];\n};\n\nexport function ProgressCard({ steps = [] }: ProgressCardProps) {\n  const allComplete = steps.length > 0 && steps.every((s) => s.status === \"complete\");\n\n  return (\n    <Card className=\"!p-4 w-full max-w-[320px] bg-[oklch(from_var(--card)_l_c_h_/_0.6)] shadow-[0_0_0_1px_oklch(from_var(--border)_l_c_h_/_0.5),0_1px_3px_0_#0000000d,0_1px_2px_-1px_#0000000d]\">\n      <CardContent className=\"flex flex-col p-0\">\n        <div className=\"flex flex-col gap-1\">\n          {steps.map((step, index) => {\n            const isHighlighted = step.status === \"in_progress\" || step.status === \"error\" || step.status === \"warning\";\n            const showDescription = isHighlighted && step.description;\n            const isFinal = index === steps.length - 1 && allComplete;\n            const isLastStep = index === steps.length - 1;\n\n            return (\n              <div\n                className=\"relative flex items-start gap-3 rounded-[var(--radius)] p-3 transition-colors duration-200\"\n                key={step.id}\n              >\n                {!isLastStep && (\n                  <div\n                    className={`ease pointer-events-none absolute top-9 left-[23px] h-[calc(100%-16px)] w-px transition-colors duration-200 ${\n                      step.status === \"complete\" ? \"bg-[var(--foreground)]\" : \"bg-[var(--border)]\"\n                    }`}\n                  />\n                )}\n\n                <div className=\"flex h-6 w-6 shrink-0 items-center justify-center\">\n                  <StepIndicator isFinal={isFinal} status={step.status} />\n                </div>\n\n                <div className=\"flex min-h-6 flex-col gap-0.5 pt-0.5\">\n                  <span\n                    className={`font-medium text-[0.9375rem] transition-colors duration-200 ${getTitleClassName(step.status)} ${\n                      step.status === \"in_progress\"\n                        ? \"animate-shimmer bg-[length:200%_100%] bg-[linear-gradient(90deg,var(--muted-foreground)_0%,var(--muted-foreground)_40%,color-mix(in_oklch,var(--foreground)_50%,var(--muted-foreground))_50%,var(--muted-foreground)_60%,var(--muted-foreground)_100%)] bg-clip-text [-webkit-background-clip:text] [-webkit-text-fill-color:transparent] motion-reduce:animate-none motion-reduce:bg-none motion-reduce:[-webkit-text-fill-color:var(--muted-foreground)]\"\n                        : \"\"\n                    }`}\n                  >\n                    {step.title}\n                  </span>\n                  {step.description && (\n                    <div\n                      className={`grid transition-[grid-template-rows,opacity] duration-250 ease-[cubic-bezier(0.165,0.84,0.44,1)] ${\n                        showDescription ? \"grid-rows-[1fr] opacity-100\" : \"grid-rows-[0fr] opacity-0\"\n                      }`}\n                    >\n                      <span\n                        className={`overflow-hidden text-[0.8125rem] ${step.status === \"error\" ? \"text-[var(--destructive-foreground)]\" : \"text-[var(--muted-foreground)]\"}`}\n                      >\n                        {step.description}\n                      </span>\n                    </div>\n                  )}\n                </div>\n              </div>\n            );\n          })}\n        </div>\n      </CardContent>\n    </Card>\n  );\n}\n",
      "type": "registry:file",
      "target": "~/components/blocks/card-progress/progress-card.tsx"
    }
  ]
}