{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tour",
  "type": "registry:component",
  "title": "Tour",
  "description": "Guided onboarding flow for introducing content or interface patterns.",
  "dependencies": [
    "@vllnt/ui@^0.2.1"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/tour/tour.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\n\nimport type { ReactNode } from \"react\";\n\nimport { cn } from \"@vllnt/ui\";\nimport { Badge } from \"@vllnt/ui\";\nimport { Button } from \"@vllnt/ui\";\nimport { Card, CardContent, CardFooter, CardHeader, CardTitle } from \"@vllnt/ui\";\n\nexport type TourStep = {\n  badge?: string;\n  description: ReactNode;\n  hint?: ReactNode;\n  id: string;\n  media?: ReactNode;\n  title: string;\n};\n\nexport type TourProps = {\n  className?: string;\n  defaultStep?: number;\n  onComplete?: () => void;\n  onStepChange?: (stepIndex: number, step: TourStep) => void;\n  steps: TourStep[];\n};\n\ntype TourHeaderProps = {\n  progress: number;\n  step: TourStep;\n  stepIndex: number;\n  totalSteps: number;\n};\n\nfunction TourHeader({\n  progress,\n  step,\n  stepIndex,\n  totalSteps,\n}: TourHeaderProps): ReactNode {\n  return (\n    <CardHeader className=\"gap-4 border-b bg-background/70\">\n      <div className=\"flex items-center justify-between gap-3\">\n        <div className=\"space-y-1\">\n          <div className=\"flex items-center gap-2\">\n            <Badge variant=\"secondary\">Tour</Badge>\n            {step.badge ? <Badge variant=\"outline\">{step.badge}</Badge> : null}\n          </div>\n          <CardTitle>{step.title}</CardTitle>\n        </div>\n        <span className=\"text-sm text-muted-foreground\">\n          {stepIndex + 1}/{totalSteps}\n        </span>\n      </div>\n      <div className=\"h-1 rounded-full bg-muted\">\n        <div\n          className=\"h-full rounded-full bg-primary transition-all\"\n          style={{ width: `${progress}%` }}\n        />\n      </div>\n    </CardHeader>\n  );\n}\n\ntype TourFooterProps = {\n  currentStep: number;\n  isFirstStep: boolean;\n  isLastStep: boolean;\n  onComplete?: () => void;\n  onStepSelect: (stepIndex: number) => void;\n  steps: TourStep[];\n};\n\nfunction TourFooter({\n  currentStep,\n  isFirstStep,\n  isLastStep,\n  onComplete,\n  onStepSelect,\n  steps,\n}: TourFooterProps): ReactNode {\n  return (\n    <CardFooter className=\"flex items-center justify-between gap-3 border-t bg-background/70 px-6 py-4\">\n      <Button\n        disabled={isFirstStep}\n        onClick={() => {\n          onStepSelect(currentStep - 1);\n        }}\n        variant=\"outline\"\n      >\n        Previous\n      </Button>\n      <div className=\"flex gap-2\">\n        {steps.map((step, index) => (\n          <button\n            aria-label={`Go to ${step.title}`}\n            className={cn(\n              \"size-2.5 rounded-full transition-colors\",\n              index === currentStep ? \"bg-primary\" : \"bg-muted-foreground/30\",\n            )}\n            key={step.id}\n            onClick={() => {\n              onStepSelect(index);\n            }}\n            type=\"button\"\n          />\n        ))}\n      </div>\n      {isLastStep ? (\n        <Button\n          onClick={() => {\n            onComplete?.();\n          }}\n        >\n          Finish\n        </Button>\n      ) : (\n        <Button\n          onClick={() => {\n            onStepSelect(currentStep + 1);\n          }}\n        >\n          Next\n        </Button>\n      )}\n    </CardFooter>\n  );\n}\n\nexport function Tour({\n  className,\n  defaultStep = 0,\n  onComplete,\n  onStepChange,\n  steps,\n}: TourProps): ReactNode {\n  const [currentStep, setCurrentStep] = useState(defaultStep);\n\n  if (steps.length === 0) {\n    return null;\n  }\n\n  const activeStep = steps[currentStep];\n  const isFirstStep = currentStep === 0;\n  const isLastStep = currentStep === steps.length - 1;\n  const progress = ((currentStep + 1) / steps.length) * 100;\n\n  if (!activeStep) {\n    return null;\n  }\n\n  const handleStepSelect = (stepIndex: number): void => {\n    const nextStep = steps[stepIndex];\n\n    if (!nextStep) {\n      return;\n    }\n\n    setCurrentStep(stepIndex);\n    onStepChange?.(stepIndex, nextStep);\n  };\n\n  return (\n    <Card\n      className={cn(\n        \"my-6 overflow-hidden border-primary/20 bg-gradient-to-br from-background to-primary/5\",\n        className,\n      )}\n    >\n      <TourHeader\n        progress={progress}\n        step={activeStep}\n        stepIndex={currentStep}\n        totalSteps={steps.length}\n      />\n      <CardContent className=\"space-y-4 p-6\">\n        {activeStep.media ? (\n          <div className=\"rounded-lg border bg-card p-4\">\n            {activeStep.media}\n          </div>\n        ) : null}\n        <div className=\"text-sm text-muted-foreground [&>p]:mb-3\">\n          {activeStep.description}\n        </div>\n        {activeStep.hint ? (\n          <div className=\"rounded-lg border border-dashed bg-muted/50 p-3 text-sm text-muted-foreground\">\n            {activeStep.hint}\n          </div>\n        ) : null}\n      </CardContent>\n      <TourFooter\n        currentStep={currentStep}\n        isFirstStep={isFirstStep}\n        isLastStep={isLastStep}\n        onComplete={onComplete}\n        onStepSelect={handleStepSelect}\n        steps={steps}\n      />\n    </Card>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "version": "0.2.1",
  "stability": "stable"
}
