{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "error8",
  "title": "404 With Redirect Countdown",
  "description": "404 page that counts down to an automatic redirect and calls onRedirect once it reaches zero, with a cancel button that stops the timer and a manual go-now link.",
  "dependencies": [
    "clsx",
    "tailwind-merge",
    "lucide-react"
  ],
  "registryDependencies": [
    "button"
  ],
  "files": [
    {
      "path": "registry/error8/error8.tsx",
      "content": "\"use client\";\n\nimport Link from \"next/link\";\nimport * as React from \"react\";\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\n\ninterface ActionLink {\n  label: string;\n  href: string;\n}\n\ninterface Error8Labels {\n  redirect?: string;\n  seconds?: string;\n  cancel?: string;\n  canceled?: string;\n}\n\ninterface Error8Props {\n  code?: string;\n  heading?: string;\n  description?: string;\n  seconds?: number;\n  labels?: Error8Labels;\n  action?: ActionLink;\n  onRedirect?: () => void;\n  className?: string;\n}\n\nexport const error8Demo: Error8Props = {\n  code: \"404\",\n  heading: \"This page does not exist\",\n  description:\n    \"Nothing to see here. We will take you somewhere useful unless you would rather stay.\",\n  seconds: 10,\n  labels: {\n    redirect: \"Redirecting to the homepage in\",\n    seconds: \"seconds\",\n    cancel: \"Stay on this page\",\n    canceled: \"Automatic redirect canceled.\",\n  },\n  action: {\n    label: \"Go now\",\n    href: \"https://beste.co\",\n  },\n};\n\nexport function Error8({\n  code,\n  heading,\n  description,\n  seconds,\n  labels = {},\n  action,\n  onRedirect,\n  className,\n}: Error8Props) {\n  const {\n    redirect: redirectLabel,\n    seconds: secondsLabel,\n    cancel: cancelLabel,\n    canceled: canceledLabel,\n  } = labels;\n\n  const [remaining, setRemaining] = React.useState(seconds ?? 0);\n  const [canceled, setCanceled] = React.useState(false);\n  const hasFired = React.useRef(false);\n\n  React.useEffect(() => {\n    if (canceled || remaining <= 0) return;\n    const timer = setTimeout(() => setRemaining((value) => value - 1), 1000);\n    return () => clearTimeout(timer);\n  }, [canceled, remaining]);\n\n  React.useEffect(() => {\n    if (!seconds || canceled || remaining > 0 || hasFired.current) return;\n    hasFired.current = true;\n    onRedirect?.();\n  }, [seconds, canceled, remaining, onRedirect]);\n\n  return (\n    <section className={cn(\"py-16 md:py-24 w-full\", className)}>\n      <div className=\"mx-auto max-w-xl px-4 text-center md:px-6\">\n        {code && (\n          <p className=\"text-sm font-medium uppercase tracking-wider text-muted-foreground\">\n            {code}\n          </p>\n        )}\n\n        {heading && (\n          <h1 className=\"mt-4 text-balance text-3xl font-bold tracking-tight md:text-4xl\">\n            {heading}\n          </h1>\n        )}\n\n        {description && (\n          <p className=\"mt-4 text-balance text-base text-muted-foreground md:text-lg\">\n            {description}\n          </p>\n        )}\n\n        <p aria-live=\"polite\" className=\"mt-8 text-base text-muted-foreground\">\n          {canceled ? (\n            canceledLabel\n          ) : (\n            <>\n              {redirectLabel}{\" \"}\n              <span className=\"font-semibold text-foreground\">{remaining}</span>{\" \"}\n              {secondsLabel}\n            </>\n          )}\n        </p>\n\n        <div className=\"mt-6 flex flex-wrap justify-center gap-3\">\n          {action && (\n            <Button size=\"lg\" asChild>\n              <Link href={action.href}>{action.label}</Link>\n            </Button>\n          )}\n          {cancelLabel && !canceled && (\n            <Button\n              type=\"button\"\n              variant=\"outline\"\n              size=\"lg\"\n              onClick={() => setCanceled(true)}\n            >\n              {cancelLabel}\n            </Button>\n          )}\n        </div>\n      </div>\n    </section>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/beste/block/error8.tsx"
    }
  ],
  "type": "registry:block"
}