{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "glass-navbar",
  "title": "Glass navbar",
  "description": "A sticky top bar on frosted glass in three styles, solid when the visitor asks for less transparency or more contrast.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/manniche/glass-navbar/glass-navbar.tsx",
      "content": "import { Menu, X } from 'lucide-react'\nimport { useEffect, useId, useRef, useState, type ReactNode } from 'react'\nimport { cn } from '@/lib/utils'\n\nexport type GlassNavLink = { href: string; label: string }\n\nexport type GlassNavbarProps = {\n  brand: ReactNode\n  links: GlassNavLink[]\n  /** The href of the page the visitor is on; that link gets aria-current. */\n  current?: string\n  /** A button or link at the end, e.g. \"Book a call\". */\n  action?: ReactNode\n  /**\n   * frosted: a full-width bar, always glass.\n   * floating: a pill that floats clear of the edges.\n   * scroll: over the hero with white text on a soft shade, glass once the page has scrolled.\n   *   Use it on a dark or photo hero; the shade keeps the text at 4.5:1 on mid-tone colours.\n   */\n  variant?: 'frosted' | 'floating' | 'scroll'\n  className?: string\n}\n\n// The glass in one place. The tint is strong enough that text keeps at least 4.5:1 over pure black or\n// pure white behind it, in both themes. Without backdrop-filter, with reduced transparency or with more\n// contrast asked for, the bar turns solid.\nconst glass =\n  'border-border/60 bg-background/75 backdrop-blur-2xl backdrop-saturate-150 ' +\n  'supports-[not(backdrop-filter:blur(1px))]:bg-background ' +\n  '[@media(prefers-reduced-transparency:reduce)]:bg-background [@media(prefers-reduced-transparency:reduce)]:backdrop-blur-none ' +\n  'contrast-more:border-border contrast-more:bg-background contrast-more:backdrop-blur-none'\n\n/** A sticky top navigation on frosted glass, with a menu button below the sm breakpoint. */\nexport function GlassNavbar({ brand, links, current, action, variant = 'frosted', className }: GlassNavbarProps) {\n  const [open, setOpen] = useState(false)\n  const [scrolled, setScrolled] = useState(false)\n  const sentinel = useRef<HTMLDivElement>(null)\n  const menuId = useId()\n\n  // A one-pixel marker above the bar: once it leaves the view, the page has scrolled.\n  // Works inside any scroll container, not only the window.\n  useEffect(() => {\n    if (variant !== 'scroll' || !sentinel.current) return\n    const io = new IntersectionObserver(([e]) => setScrolled(!e.isIntersecting))\n    io.observe(sentinel.current)\n    return () => io.disconnect()\n  }, [variant])\n\n  useEffect(() => {\n    if (!open) return\n    const close = (e: KeyboardEvent) => e.key === 'Escape' && setOpen(false)\n    addEventListener('keydown', close)\n    return () => removeEventListener('keydown', close)\n  }, [open])\n\n  const solid = variant !== 'scroll' || scrolled || open\n  const floating = variant === 'floating'\n\n  return (\n    <>\n      {variant === 'scroll' && <div ref={sentinel} aria-hidden className=\"h-px -mb-px\" />}\n      <header data-hero={!solid} className={cn('group/glass sticky top-0 z-30', floating && 'px-3 pt-3', className)}>\n        <div\n          className={cn(\n            'border transition-[background-color,border-color,box-shadow,backdrop-filter] duration-300 ease-out motion-reduce:transition-none',\n            floating\n              ? 'mx-auto max-w-3xl rounded-2xl shadow-[inset_0_1px_0_0_rgb(255_255_255/0.25),0_8px_24px_-12px_rgb(0_0_0/0.25)]'\n              : 'border-x-0 border-t-0',\n            solid ? glass : 'border-transparent bg-linear-to-b from-black/45 to-transparent',\n          )}\n        >\n          <nav aria-label=\"Main\" className={cn('flex min-h-14 items-center gap-4', floating ? 'px-3' : 'mx-auto max-w-5xl px-4')}>\n            <div className=\"mr-auto flex items-center text-sm font-semibold group-data-[hero=true]/glass:text-white\">{brand}</div>\n            <ul className=\"hidden items-center gap-1 sm:flex\">\n              {links.map((l) => (\n                <li key={l.href}>\n                  <a\n                    href={l.href}\n                    aria-current={l.href === current ? 'page' : undefined}\n                    className=\"inline-flex min-h-11 items-center rounded-lg px-3 text-sm text-muted-foreground transition-colors duration-150 hover:text-foreground aria-[current=page]:font-medium aria-[current=page]:text-foreground group-data-[hero=true]/glass:text-white/90 group-data-[hero=true]/glass:hover:text-white group-data-[hero=true]/glass:aria-[current=page]:text-white\"\n                  >\n                    {l.label}\n                  </a>\n                </li>\n              ))}\n            </ul>\n            {action && <div className=\"hidden sm:block\">{action}</div>}\n            <button\n              type=\"button\"\n              aria-expanded={open}\n              aria-controls={menuId}\n              aria-label={open ? 'Close menu' : 'Open menu'}\n              onClick={() => setOpen((o) => !o)}\n              className=\"grid size-11 place-items-center rounded-lg text-foreground sm:hidden group-data-[hero=true]/glass:text-white\"\n            >\n              {open ? <X className=\"size-5\" /> : <Menu className=\"size-5\" />}\n            </button>\n          </nav>\n          <div id={menuId} hidden={!open} className=\"border-t border-border/60 px-4 pb-3 sm:hidden\">\n            <ul className=\"grid pt-2\">\n              {links.map((l) => (\n                <li key={l.href}>\n                  <a\n                    href={l.href}\n                    aria-current={l.href === current ? 'page' : undefined}\n                    onClick={() => setOpen(false)}\n                    className=\"flex min-h-11 items-center text-base text-muted-foreground aria-[current=page]:font-medium aria-[current=page]:text-foreground\"\n                  >\n                    {l.label}\n                  </a>\n                </li>\n              ))}\n            </ul>\n            {action && <div className=\"pt-2\">{action}</div>}\n          </div>\n        </div>\n      </header>\n    </>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "categories": [
    "navigation"
  ],
  "type": "registry:component"
}