{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "header-announcement-stack",
  "title": "Header — Announcement Stack",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/header-announcement-stack/HeaderAnnouncementStack.tsx",
      "content": "'use client'\n\nimport { useEffect, useState } from 'react'\nimport { ArrowRight, Menu, Layers, X } from 'lucide-react'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Separator } from '@/components/ui/separator'\nimport { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '@/components/ui/sheet'\n\nconst STORAGE_KEY = 'uipkge:announcement-dismissed'\n\nconst links = [\n  { label: 'Platform', href: '#platform' },\n  { label: 'Pricing', href: '#pricing' },\n  { label: 'Customers', href: '#customers' },\n  { label: 'Docs', href: '#docs' },\n]\n\nexport function HeaderAnnouncementStack() {\n  // Rendered on the server and dismissed only on the client, so there is no\n  // flash of a strip that then vanishes.\n  const [dismissed, setDismissed] = useState(false)\n  const [open, setOpen] = useState(false)\n\n  useEffect(() => {\n    try {\n      setDismissed(window.sessionStorage.getItem(STORAGE_KEY) === '1')\n    } catch {\n      setDismissed(false)\n    }\n  }, [])\n\n  function dismiss() {\n    setDismissed(true)\n    try {\n      window.sessionStorage.setItem(STORAGE_KEY, '1')\n    } catch {\n      // Blocked storage: the dismissal still holds for this page view.\n    }\n  }\n\n  return (\n    <div data-slot=\"header-announcement-stack\" className=\"sticky top-0 z-40\">\n      {!dismissed && (\n        <div className=\"border-border bg-muted/60 border-b backdrop-blur\">\n          <div className=\"mx-auto flex h-10 max-w-6xl items-center gap-3 px-6 text-sm\">\n            <Badge variant=\"secondary\" className=\"shrink-0\">\n              New\n            </Badge>\n            <p className=\"min-w-0 truncate\">\n              Row-level scoping now evaluates against SCIM groups.{' '}\n              <a href=\"#changelog\" className=\"hover:text-foreground underline underline-offset-4\">\n                Read the changelog\n              </a>\n            </p>\n            <ArrowRight className=\"text-muted-foreground hidden size-3.5 shrink-0 sm:block\" aria-hidden=\"true\" />\n            <Button\n              variant=\"ghost\"\n              size=\"icon\"\n              className=\"ml-auto size-7 shrink-0\"\n              aria-label=\"Dismiss announcement\"\n              onClick={dismiss}\n            >\n              <X className=\"size-3.5\" aria-hidden=\"true\" />\n            </Button>\n          </div>\n        </div>\n      )}\n\n      <header className=\"border-border bg-background/90 border-b backdrop-blur\">\n        <div className=\"mx-auto flex h-16 max-w-6xl items-center gap-6 px-6\">\n          <a href=\"#top\" className=\"flex shrink-0 items-center gap-2 font-semibold tracking-tight\">\n            <Layers className=\"text-primary size-5\" aria-hidden=\"true\" />\n            Northwind\n          </a>\n\n          <nav className=\"hidden items-center gap-1 md:flex\" aria-label=\"Primary\">\n            {links.map((link) => (\n              <a\n                key={link.href}\n                href={link.href}\n                className=\"text-muted-foreground hover:text-foreground hover:bg-muted focus-visible:ring-ring rounded-md px-3 py-1.5 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none\"\n              >\n                {link.label}\n              </a>\n            ))}\n          </nav>\n\n          <div className=\"ml-auto hidden items-center gap-2 md:flex\">\n            <Button variant=\"ghost\" size=\"sm\">\n              Sign in\n            </Button>\n            <Button size=\"sm\">Book a demo</Button>\n          </div>\n\n          <Sheet open={open} onOpenChange={setOpen}>\n            <SheetTrigger asChild>\n              <Button variant=\"ghost\" size=\"icon\" className=\"ml-auto md:hidden\" aria-label=\"Open navigation menu\">\n                <Menu className=\"size-5\" aria-hidden=\"true\" />\n              </Button>\n            </SheetTrigger>\n            <SheetContent side=\"right\" className=\"w-72\">\n              <SheetHeader>\n                <SheetTitle>Menu</SheetTitle>\n              </SheetHeader>\n              <nav className=\"mt-6 grid gap-1\" aria-label=\"Mobile\">\n                {links.map((link) => (\n                  <a\n                    key={link.href}\n                    href={link.href}\n                    className=\"hover:bg-muted rounded-md px-3 py-2 text-sm font-medium transition-colors\"\n                    onClick={() => setOpen(false)}\n                  >\n                    {link.label}\n                  </a>\n                ))}\n              </nav>\n              <Separator className=\"my-5\" />\n              <div className=\"grid gap-2\">\n                <Button variant=\"outline\">Sign in</Button>\n                <Button>Book a demo</Button>\n              </div>\n            </SheetContent>\n          </Sheet>\n        </div>\n      </header>\n    </div>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/HeaderAnnouncementStack.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/separator.json",
    "https://uipkge.dev/r/react/sheet.json"
  ],
  "description": "Two-tier site header: a dismissible announcement strip above a sticky navbar, where dismissing the strip collapses it and leaves the navbar flush against the viewport top.",
  "categories": [
    "marketing"
  ],
  "deprecated": true,
  "replacedBy": "header"
}