{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "announcement-4",
  "title": "Sale Countdown Promo Bar",
  "description": "Sticky promo announcement bar with a live sale countdown ticking days, hours, minutes, and seconds beside a shop the sale button.",
  "dependencies": [
    "@base-ui/react"
  ],
  "registryDependencies": [
    "button"
  ],
  "files": [
    {
      "path": "registry/blocks/announcement/4/announcement-block.tsx",
      "content": "\"use client\"\n\nimport { useEffect, useState } from \"react\"\nimport { Button } from \"@/components/ui/button\"\nimport { IconPlaceholder } from \"@/components/icons/icon-placeholder\"\n\nconst SALE_DURATION_MS =\n  2 * 24 * 60 * 60 * 1000 + 11 * 60 * 60 * 1000 + 34 * 60 * 1000 + 12 * 1000\n\ntype TimeLeft = {\n  days: number\n  hours: number\n  minutes: number\n  seconds: number\n}\n\nfunction getTimeLeft(diffMs: number): TimeLeft {\n  const diff = Math.max(0, diffMs)\n  const totalSeconds = Math.floor(diff / 1000)\n  return {\n    days: Math.floor(totalSeconds / 86400),\n    hours: Math.floor((totalSeconds % 86400) / 3600),\n    minutes: Math.floor((totalSeconds % 3600) / 60),\n    seconds: totalSeconds % 60,\n  }\n}\n\nfunction pad(value: number): string {\n  return value.toString().padStart(2, \"0\")\n}\n\nexport default function AnnouncementBlock() {\n  const [timeLeft, setTimeLeft] = useState<TimeLeft>(() =>\n    getTimeLeft(SALE_DURATION_MS)\n  )\n\n  useEffect(() => {\n    const deadline = Date.now() + SALE_DURATION_MS\n    const interval = setInterval(() => {\n      setTimeLeft(getTimeLeft(deadline - Date.now()))\n    }, 1000)\n\n    return () => clearInterval(interval)\n  }, [])\n\n  return (\n    <section className=\"flex min-h-svh w-full flex-col bg-muted/30 text-foreground\">\n      <div className=\"w-full bg-primary text-primary-foreground\">\n        <div className=\"mx-auto flex w-full max-w-6xl flex-col items-center gap-3 px-6 py-3 sm:flex-row sm:justify-between\">\n          <div className=\"flex flex-col items-center gap-2.5 sm:flex-row sm:gap-3\">\n            <span className=\"flex items-center gap-2 text-sm font-semibold\">\n              <IconPlaceholder\n                lucide=\"Flame\"\n                tabler=\"IconFlame\"\n                hugeicons=\"FireIcon\"\n                phosphor=\"Fire\"\n                remixicon=\"RiFireLine\"\n                className=\"size-4 shrink-0\"\n                aria-hidden=\"true\"\n              />\n              Summer Sale, up to 40% off\n            </span>\n            <span className=\"hidden h-4 w-px bg-primary-foreground/30 sm:block\" />\n            <span className=\"flex items-center gap-2 text-sm\">\n              <span className=\"text-primary-foreground/80\">Sale ends in</span>\n              <span className=\"flex items-center gap-1 font-mono text-sm font-semibold tabular-nums\">\n                <span className=\"rounded-md bg-primary-foreground/15 px-1.5 py-0.5\">\n                  {pad(timeLeft.days)}d\n                </span>\n                <span className=\"rounded-md bg-primary-foreground/15 px-1.5 py-0.5\">\n                  {pad(timeLeft.hours)}h\n                </span>\n                <span className=\"rounded-md bg-primary-foreground/15 px-1.5 py-0.5\">\n                  {pad(timeLeft.minutes)}m\n                </span>\n                <span className=\"rounded-md bg-primary-foreground/15 px-1.5 py-0.5\">\n                  {pad(timeLeft.seconds)}s\n                </span>\n              </span>\n            </span>\n          </div>\n          <Button\n            size=\"sm\"\n            variant=\"secondary\"\n            render={<a href=\"#\" />}\n            nativeButton={false}\n            className=\"w-full sm:w-auto\"\n          >\n            Shop The Sale\n            <IconPlaceholder\n              lucide=\"ArrowRight\"\n              tabler=\"IconArrowRight\"\n              hugeicons=\"ArrowRightIcon\"\n              phosphor=\"ArrowRight\"\n              remixicon=\"RiArrowRightLine\"\n              data-icon=\"inline-end\"\n              aria-hidden=\"true\"\n            />\n          </Button>\n        </div>\n      </div>\n\n      <div\n        aria-hidden=\"true\"\n        className=\"mx-auto w-4/5 max-w-5xl flex-1 px-6 py-10\"\n      >\n        <div className=\"mb-6 flex items-center justify-between\">\n          <div className=\"h-6 w-28 rounded-md bg-muted\" />\n          <div className=\"hidden items-center gap-3 sm:flex\">\n            <div className=\"h-3 w-14 rounded-md bg-muted\" />\n            <div className=\"h-3 w-14 rounded-md bg-muted\" />\n            <div className=\"h-7 w-16 rounded-md bg-muted\" />\n          </div>\n        </div>\n\n        <div className=\"space-y-2\">\n          <div className=\"h-6 w-1/2 rounded-md bg-muted\" />\n          <div className=\"h-3 w-full rounded-md bg-muted\" />\n          <div className=\"h-3 w-4/5 rounded-md bg-muted\" />\n        </div>\n\n        <div className=\"mt-8 grid gap-3 sm:grid-cols-3\">\n          {Array.from({ length: 3 }).map((_, index) => (\n            <div key={index} className=\"h-24 rounded-md bg-muted\" />\n          ))}\n        </div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "meta": {
    "height": "384px",
    "tier": "free"
  },
  "docs": "Requires a `base-*` style in components.json (the `shadcn init` default). Legacy `new-york`/`radix-*` styles install Radix primitives, which reject the `render` prop this block uses.",
  "categories": [
    "announcement"
  ],
  "type": "registry:block"
}