{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "announcement-banner",
  "title": "Announcement Banner",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-svelte/blocks/announcement-banner/AnnouncementBanner.svelte",
      "content": "<script lang=\"ts\" module>\n  export interface AnnouncementItem {\n    id: string\n    category: 'release' | 'security' | 'maintenance' | 'feature'\n    badgeText: string\n    title: string\n    actionLabel: string\n    actionUrl?: string\n    cliSnippet?: string\n  }\n\n  export interface AnnouncementBannerProps {\n    variant?: 'floating-pill' | 'top-bar' | 'interactive-ticker'\n    autoplay?: boolean\n    class?: string\n  }\n</script>\n\n<script lang=\"ts\">\n  import { onDestroy, onMount } from 'svelte'\n  import { ArrowRight, ChevronLeft, ChevronRight, Megaphone, Terminal, X } from '@lucide/svelte'\n  import { Badge } from '$lib/components/ui/badge'\n  import { cn } from '$lib/utils'\n\n  let { variant = 'interactive-ticker', autoplay = true, class: className }: AnnouncementBannerProps = $props()\n\n  const announcements: AnnouncementItem[] = [\n    {\n      id: 'ann-1',\n      category: 'release',\n      badgeText: 'v2.4.0 Release',\n      title: 'Tailwind CSS v4 OKLCH tokens & 281+ production workbenches are live.',\n      actionLabel: 'Read Changelog',\n      actionUrl: 'https://uipkge.dev/changelog',\n      cliSnippet: 'npx shadcn-svelte@latest add https://uipkge.dev/r/svelte/init.json',\n    },\n    {\n      id: 'ann-2',\n      category: 'feature',\n      badgeText: 'Multi-Framework',\n      title: 'Svelte 5 runes parity with the Vue 3.5 & React 19 registries, zero runtime CSS.',\n      actionLabel: 'Explore Parity Matrix',\n      actionUrl: 'https://uipkge.dev/components',\n      cliSnippet: 'npx shadcn-svelte@latest add https://uipkge.dev/r/svelte/button.json',\n    },\n    {\n      id: 'ann-3',\n      category: 'security',\n      badgeText: 'Security Notice',\n      title: 'Upstream dependency security patches verified and updated.',\n      actionLabel: 'Security Advisory',\n      actionUrl: 'https://uipkge.dev/security',\n    },\n  ]\n\n  let currentIndex = $state(0)\n  let dismissed = $state(false)\n  let isPaused = $state(false)\n  let copiedCli = $state(false)\n\n  let timer: ReturnType<typeof setInterval> | undefined\n\n  function nextAnnouncement() {\n    currentIndex = (currentIndex + 1) % announcements.length\n  }\n\n  function prevAnnouncement() {\n    currentIndex = (currentIndex - 1 + announcements.length) % announcements.length\n  }\n\n  function startAutoplay() {\n    if (!autoplay) return\n    stopAutoplay()\n    timer = setInterval(() => {\n      if (!isPaused) nextAnnouncement()\n    }, 6000)\n  }\n\n  function stopAutoplay() {\n    if (timer) clearInterval(timer)\n  }\n\n  onMount(startAutoplay)\n  onDestroy(stopAutoplay)\n\n  function copyCliSnippet(snippet?: string) {\n    if (!snippet) return\n    navigator.clipboard.writeText(snippet)\n    copiedCli = true\n    setTimeout(() => (copiedCli = false), 2000)\n  }\n\n  const current = $derived(announcements[currentIndex])\n</script>\n\n{#if !dismissed}\n  <div\n    data-slot=\"announcement-banner\"\n    data-variant={variant}\n    role=\"region\"\n    aria-label=\"Announcement\"\n    class={cn('relative z-50 transition-colors duration-200', className)}\n    onmouseenter={() => (isPaused = true)}\n    onmouseleave={() => (isPaused = false)}\n  >\n    <!-- 1. Interactive Ticker Mode (Default) -->\n    {#if variant === 'interactive-ticker'}\n      <div\n        class=\"bg-muted/70 border-border text-foreground flex items-center justify-between gap-3 overflow-hidden border-b px-4 py-2 text-xs shadow-xs backdrop-blur-md\"\n      >\n        <div class=\"mx-auto flex w-full max-w-6xl items-center justify-between gap-4\">\n          <!-- Left: Status Beacon & Item Indicator -->\n          <div class=\"flex shrink-0 items-center gap-3\">\n            <div class=\"text-muted-foreground flex items-center gap-1.5 font-mono text-xs\">\n              <span class=\"bg-primary size-2 animate-pulse rounded-full\"></span>\n              <span class=\"text-foreground font-semibold\">Live Dispatch</span>\n            </div>\n\n            <Badge\n              variant=\"secondary\"\n              class={cn(\n                'px-2 py-0.5 font-mono text-xs',\n                current.category === 'release' && 'bg-primary/10 text-primary border-primary/20',\n                current.category === 'security' && 'border-warning/20 bg-warning/10 text-warning',\n                current.category === 'feature' && 'border-success/20 bg-success/10 text-success',\n              )}\n            >\n              {current.badgeText}\n            </Badge>\n          </div>\n\n          <!-- Center: Dynamic Headline & Action Link -->\n          <div class=\"flex flex-1 items-center justify-center gap-2 truncate\">\n            <p class=\"text-foreground truncate font-medium\">\n              {current.title}\n            </p>\n            {#if current.actionUrl}\n              <a\n                href={current.actionUrl}\n                class=\"text-primary hidden shrink-0 items-center gap-1 font-semibold hover:underline sm:inline-flex\"\n              >\n                {current.actionLabel} <ArrowRight class=\"size-3\" />\n              </a>\n            {/if}\n          </div>\n\n          <!-- Right: Ticker Navigation & CLI / Dismiss -->\n          <div class=\"flex shrink-0 items-center gap-2\">\n            {#if current.cliSnippet}\n              <button\n                type=\"button\"\n                class=\"bg-background border-border text-muted-foreground hover:text-foreground hidden items-center gap-1.5 rounded border px-2 py-0.5 font-mono text-xs transition-colors md:inline-flex\"\n                onclick={() => copyCliSnippet(current.cliSnippet)}\n              >\n                <Terminal class=\"text-primary size-3\" />\n                <span>{copiedCli ? 'Copied CLI!' : 'Copy CLI'}</span>\n              </button>\n            {/if}\n\n            <div class=\"border-border bg-background flex items-center overflow-hidden rounded-md border\">\n              <button\n                type=\"button\"\n                class=\"hover:bg-muted text-muted-foreground hover:text-foreground p-1 transition-colors\"\n                aria-label=\"Previous announcement\"\n                onclick={prevAnnouncement}\n              >\n                <ChevronLeft class=\"size-3.5\" />\n              </button>\n              <span class=\"text-muted-foreground px-1.5 font-mono text-xs\">\n                {currentIndex + 1}/{announcements.length}\n              </span>\n              <button\n                type=\"button\"\n                class=\"hover:bg-muted text-muted-foreground hover:text-foreground p-1 transition-colors\"\n                aria-label=\"Next announcement\"\n                onclick={nextAnnouncement}\n              >\n                <ChevronRight class=\"size-3.5\" />\n              </button>\n            </div>\n\n            <button\n              type=\"button\"\n              aria-label=\"Dismiss banner\"\n              class=\"text-muted-foreground hover:text-foreground hover:bg-muted rounded-md p-1 transition-colors\"\n              onclick={() => (dismissed = true)}\n            >\n              <X class=\"size-3.5\" />\n            </button>\n          </div>\n        </div>\n      </div>\n\n      <!-- 2. Floating Pill Mode -->\n    {:else if variant === 'floating-pill'}\n      <div class=\"mx-auto w-fit max-w-2xl px-4 py-2\">\n        <div\n          class=\"bg-card/90 border-border text-foreground hover:border-primary/40 flex items-center gap-3 rounded-full border py-1.5 pr-2 pl-3 text-xs shadow-md backdrop-blur-md transition-colors\"\n        >\n          <Badge variant=\"secondary\" class=\"bg-primary/10 text-primary border-primary/20 px-2 py-0.5 font-mono text-xs\">\n            {current.badgeText}\n          </Badge>\n          <p class=\"text-foreground max-w-sm truncate font-medium\">\n            {current.title}\n          </p>\n          {#if current.actionUrl}\n            <a\n              href={current.actionUrl}\n              class=\"text-primary inline-flex shrink-0 items-center gap-1 font-semibold hover:underline\"\n            >\n              {current.actionLabel} <ArrowRight class=\"size-3\" />\n            </a>\n          {/if}\n          <button\n            type=\"button\"\n            aria-label=\"Dismiss announcement\"\n            class=\"text-muted-foreground hover:text-foreground hover:bg-muted rounded-full p-1 transition-colors\"\n            onclick={() => (dismissed = true)}\n          >\n            <X class=\"size-3.5\" />\n          </button>\n        </div>\n      </div>\n\n      <!-- 3. Top Solid Bar Mode -->\n    {:else}\n      <div class=\"bg-primary text-primary-foreground flex items-center justify-between gap-3 px-4 py-2 text-xs shadow-xs\">\n        <div class=\"mx-auto flex w-full max-w-6xl items-center justify-between gap-4\">\n          <div class=\"flex items-center gap-2 truncate\">\n            <Megaphone class=\"size-4 shrink-0\" />\n            <span class=\"font-mono font-bold\">[{current.badgeText}]</span>\n            <span class=\"truncate\">{current.title}</span>\n          </div>\n          <div class=\"flex shrink-0 items-center gap-3\">\n            {#if current.actionUrl}\n              <a\n                href={current.actionUrl}\n                class=\"inline-flex items-center gap-1 font-semibold underline-offset-4 hover:underline\"\n              >\n                {current.actionLabel} <ArrowRight class=\"size-3\" />\n              </a>\n            {/if}\n            <button\n              type=\"button\"\n              aria-label=\"Dismiss banner\"\n              class=\"text-primary-foreground/80 hover:text-primary-foreground hover:bg-primary-foreground/15 rounded p-1 transition-colors\"\n              onclick={() => (dismissed = true)}\n            >\n              <X class=\"size-3.5\" />\n            </button>\n          </div>\n        </div>\n      </div>\n    {/if}\n  </div>\n{/if}\n",
      "type": "registry:block",
      "target": "~/src/lib/components/blocks/announcement-banner/AnnouncementBanner.svelte"
    }
  ],
  "dependencies": [
    "@lucide/svelte"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/svelte/badge.json"
  ],
  "description": "Interactive release, security, and maintenance broadcast center with rotating live ticker, CLI copy button, and floating pill / top-bar modes.",
  "categories": [
    "marketing"
  ],
  "deprecated": true,
  "replacedBy": "announcement"
}