{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "404-block",
  "title": "404 Block",
  "description": "A drop-in 404 block with a bold 404 and a button filled with live red lava.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "https://cloverui.xyz/r/liquid-button.json"
  ],
  "files": [
    {
      "path": "registry/clover-ui/404-block.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { useReducedMotion } from \"motion/react\";\n\nimport { cn } from \"@/lib/utils\";\nimport {\n  LiquidButton,\n  elementGradient,\n  useElementSurface,\n  type ElementColors,\n} from \"@/registry/clover-ui/liquid-button\";\n\nexport interface Block404Props extends Omit<React.ComponentProps<\"section\">, \"title\"> {\n  title?: string;\n  description?: React.ReactNode;\n  actionLabel?: string;\n  href?: string;\n  onAction?: () => void;\n}\n\nconst LAVA_TEXT: ElementColors = [\"#ff5a4a\", \"#e8261a\", \"#a80e06\"];\n\nfunction ElementText({\n  text,\n  still,\n  className,\n}: {\n  text: string;\n  still: boolean;\n  className?: string;\n}) {\n  const wrapRef = React.useRef<HTMLSpanElement>(null);\n  const canvasRef = React.useRef<HTMLCanvasElement>(null);\n  const tones = LAVA_TEXT;\n  const { ready } = useElementSurface(canvasRef, \"lava\", tones, still);\n  const [masked, setMasked] = React.useState(false);\n\n  React.useEffect(() => {\n    const wrap = wrapRef.current;\n    const canvas = canvasRef.current;\n    if (!wrap || !canvas || !ready) return;\n\n    const paintMask = () => {\n      const { width, height } = wrap.getBoundingClientRect();\n      if (!width || !height) return;\n      const dpr = Math.min(window.devicePixelRatio || 1, 2);\n      const mask = document.createElement(\"canvas\");\n      mask.width = Math.round(width * dpr);\n      mask.height = Math.round(height * dpr);\n      const ctx = mask.getContext(\"2d\");\n      if (!ctx) return;\n      const style = getComputedStyle(wrap);\n      ctx.scale(dpr, dpr);\n      ctx.font = style.font;\n      if (\"letterSpacing\" in ctx) ctx.letterSpacing = style.letterSpacing;\n      const metrics = ctx.measureText(text);\n      const ascent = metrics.fontBoundingBoxAscent;\n      const descent = metrics.fontBoundingBoxDescent;\n      ctx.fillText(text, 0, (height - ascent - descent) / 2 + ascent);\n      const url = `url(${mask.toDataURL()})`;\n      canvas.style.maskImage = url;\n      canvas.style.webkitMaskImage = url;\n      setMasked(true);\n    };\n\n    paintMask();\n    document.fonts?.ready.then(paintMask);\n    const observer = new ResizeObserver(paintMask);\n    observer.observe(wrap);\n    return () => observer.disconnect();\n  }, [ready, text]);\n\n  return (\n    <span ref={wrapRef} className={cn(\"relative inline-block whitespace-pre\", className)}>\n      <span\n        className=\"bg-clip-text text-transparent\"\n        style={{ backgroundImage: elementGradient(tones) }}\n      >\n        {text}\n      </span>\n      <canvas\n        ref={canvasRef}\n        aria-hidden\n        className={cn(\n          \"pointer-events-none absolute inset-0 size-full [mask-size:100%_100%] transition-opacity duration-500 [-webkit-mask-size:100%_100%]\",\n          ready && masked ? \"opacity-100\" : \"opacity-0\",\n        )}\n      />\n    </span>\n  );\n}\n\nfunction Block404({\n  title = \"Error\",\n  description = (\n    <>\n      Sorry, the page you were looking for <strong>doesn&apos;t exist</strong>. Check the{\" \"}\n      <strong>URL</strong> for typos, or head back <strong>home</strong>.\n    </>\n  ),\n  actionLabel = \"Back to home\",\n  href = \"/\",\n  onAction,\n  className,\n  ...props\n}: Block404Props) {\n  const still = Boolean(useReducedMotion());\n\n  return (\n    <section\n      className={cn(\"text-foreground flex w-full justify-center px-6 py-16\", className)}\n      {...props}\n    >\n      <div className=\"flex w-full max-w-md flex-col items-start text-left\">\n        <h1 className=\"flex flex-wrap items-baseline gap-x-[0.25em] text-3xl leading-tight tracking-tight sm:text-4xl\">\n          <span className=\"text-muted-foreground font-semibold\">{title}</span>\n          <ElementText text=\"404\" still={still} className=\"font-bold\" />\n        </h1>\n\n        {description && (\n          <p className=\"text-muted-foreground [&_strong]:text-foreground mt-3 text-[15px] leading-relaxed text-pretty sm:text-base [&_a]:underline-offset-4 [&_a:hover]:underline [&_strong]:font-semibold\">\n            {description}\n          </p>\n        )}\n\n        {onAction ? (\n          <LiquidButton onClick={onAction} className=\"mt-6\">\n            {actionLabel}\n          </LiquidButton>\n        ) : (\n          <LiquidButton asChild className=\"mt-6\">\n            <a href={href}>{actionLabel}</a>\n          </LiquidButton>\n        )}\n      </div>\n    </section>\n  );\n}\n\nexport { Block404 };\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}