{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "extends": "none",
  "name": "navbar",
  "title": "navbar",
  "description": "navbar",
  "dependencies": [
    "@heroicons/react",
    "motion",
    "tailwind-merge"
  ],
  "registryDependencies": [
    "https://intentui.com/r/link",
    "https://intentui.com/r/use-mobile",
    "https://intentui.com/r/primitive",
    "https://intentui.com/r/button",
    "https://intentui.com/r/separator",
    "https://intentui.com/r/sheet"
  ],
  "files": [
    {
      "path": "src/components/ui/navbar.tsx",
      "content": "'use client'\n\nimport { Bars2Icon } from '@heroicons/react/20/solid'\nimport { LayoutGroup, motion } from 'motion/react'\nimport { createContext, use, useCallback, useId, useMemo, useState } from 'react'\nimport { twJoin, twMerge } from 'tailwind-merge'\nimport { Link, type LinkProps } from '@/components/ui/link'\nimport { useIsMobile } from '@/hooks/use-mobile'\nimport { cx } from '@/lib/primitive'\nimport { Button, type ButtonProps } from './button'\nimport { Separator } from './separator'\nimport { Sheet, SheetBody, SheetContent } from './sheet'\n\ninterface NavbarContextProps {\n  open: boolean\n  setOpen: (open: boolean) => void\n  isMobile: boolean\n  toggleNavbar: () => void\n}\n\nconst NavbarContext = createContext<NavbarContextProps | null>(null)\n\nconst useNavbar = () => {\n  const context = use(NavbarContext)\n  if (!context) {\n    throw new Error('useNavbar must be used within a NavbarProvider.')\n  }\n\n  return context\n}\n\ninterface NavbarProviderProps extends React.ComponentProps<'div'> {\n  defaultOpen?: boolean\n  isOpen?: boolean\n  onOpenChange?: (open: boolean) => void\n}\n\nconst NavbarProvider = ({\n  isOpen: openProp,\n  onOpenChange: setOpenProp,\n  defaultOpen = false,\n  className,\n  ...props\n}: NavbarProviderProps) => {\n  const [openInternal, setOpenInternal] = useState(defaultOpen)\n  const open = openProp ?? openInternal\n\n  const setOpen = useCallback(\n    (value: boolean | ((value: boolean) => boolean)) => {\n      if (setOpenProp) {\n        return setOpenProp?.(typeof value === 'function' ? value(open) : value)\n      }\n\n      setOpenInternal(value)\n    },\n    [setOpenProp, open]\n  )\n\n  const toggleNavbar = useCallback(() => {\n    setOpen((open) => !open)\n  }, [setOpen])\n\n  const isMobile = useIsMobile()\n\n  const contextValue = useMemo<NavbarContextProps>(\n    () => ({\n      open,\n      setOpen,\n      isMobile: isMobile ?? false,\n      toggleNavbar,\n    }),\n    [open, setOpen, isMobile, toggleNavbar]\n  )\n\n  if (isMobile === undefined) {\n    return null\n  }\n\n  return (\n    <NavbarContext value={contextValue}>\n      <div\n        className={twMerge(\n          'peer/navbar group/navbar relative isolate z-10 flex w-full flex-col',\n          'has-data-navbar-inset:min-h-svh has-data-navbar-inset:bg-navbar dark:has-data-navbar-inset:bg-bg',\n          className\n        )}\n        {...props}\n      />\n    </NavbarContext>\n  )\n}\n\ntype Intent = 'default' | 'float' | 'inset'\ntype Placement = 'top' | 'bottom'\ntype Side = 'left' | 'right'\n\ninterface StickyWithPlacement extends React.ComponentProps<'div'> {\n  isSticky: true\n  placement?: Placement\n  side?: Side\n  intent?: Intent\n}\n\ninterface NonStickyWithoutPlacement extends React.ComponentProps<'div'> {\n  isSticky?: false\n  placement?: never\n  side?: Side\n  intent?: Intent\n}\n\ntype NavbarProps = StickyWithPlacement | NonStickyWithoutPlacement\n\nconst Navbar = ({\n  children,\n  isSticky,\n  placement = 'top',\n  intent = 'default',\n  side = 'left',\n  className,\n  ref,\n  ...props\n}: NavbarProps) => {\n  const { isMobile, open, setOpen } = useNavbar()\n  if (isMobile) {\n    return (\n      <>\n        <span\n          className=\"sr-only\"\n          aria-hidden\n          data-navbar={intent}\n          data-navbar-sticky={isSticky}\n          data-placement={placement ?? undefined}\n        />\n        <Sheet isOpen={open} onOpenChange={setOpen} {...props}>\n          <SheetContent\n            side={side}\n            aria-label=\"Mobile Navbar\"\n            className=\"entering:blur-in exiting:blur-out [&>button]:hidden\"\n          >\n            <SheetBody className=\"p-[calc(var(--gutter)-(--spacing(2)))] sm:p-[calc(var(--gutter)-(--spacing(4)))]\">\n              {children}\n            </SheetBody>\n          </SheetContent>\n        </Sheet>\n      </>\n    )\n  }\n\n  return (\n    <div\n      data-navbar={intent}\n      ref={ref}\n      data-placement={placement ?? undefined}\n      data-navbar-sticky={isSticky}\n      className={twMerge([\n        'group/navbar-intent relative isolate',\n        isSticky && 'sticky top-0 z-40',\n        placement === 'top' && intent === 'float' && 'md:pt-8',\n        placement === 'bottom' && intent === 'float' && 'bottom-0 md:pb-8',\n        intent === 'float' && 'mx-auto w-full max-w-7xl px-4 xl:max-w-(--breakpoint-xl)',\n      ])}\n      {...props}\n    >\n      <div\n        className={twMerge(\n          'relative isolate hidden py-(--navbar-gutter) [--navbar-gutter:--spacing(2.5)] md:block',\n          intent === 'float' &&\n            'rounded-xl bg-bg py-0 *:data-[navbar=content]:max-w-7xl *:data-[navbar=content]:rounded-xl *:data-[navbar=content]:border *:data-[navbar=content]:bg-navbar *:data-[navbar=content]:px-4 *:data-[navbar=content]:py-(--navbar-gutter) *:data-[navbar=content]:shadow-xs',\n          ['default', 'inset'].includes(intent) && 'px-4',\n          intent === 'default' && 'border-b bg-navbar',\n          className\n        )}\n      >\n        <div\n          data-navbar=\"content\"\n          className=\"mx-auto w-full max-w-(--breakpoint-2xl) items-center md:flex\"\n        >\n          {children}\n        </div>\n      </div>\n    </div>\n  )\n}\n\nconst NavbarSection = ({ className, ...props }: React.ComponentProps<'div'>) => {\n  const id = useId()\n  return (\n    <LayoutGroup id={id}>\n      <div\n        data-slot=\"navbar-section\"\n        className={twMerge(\n          'col-span-full grid grid-cols-[auto_1fr] flex-col gap-3 gap-y-0.5 md:flex md:flex-none md:grid-cols-none md:flex-row md:items-center md:gap-2.5',\n          className\n        )}\n        {...props}\n      >\n        {props.children}\n      </div>\n    </LayoutGroup>\n  )\n}\n\ninterface NavbarItemProps extends LinkProps {\n  isCurrent?: boolean\n}\n\nconst NavbarItem = ({ className, isCurrent, ...props }: NavbarItemProps) => {\n  return (\n    <Link\n      data-slot=\"navbar-item\"\n      aria-current={isCurrent ? 'page' : undefined}\n      className={cx(\n        [\n          'href' in props ? 'cursor-pointer' : 'cursor-default',\n          'group/sidebar-item pressed:bg-secondary pressed:text-secondary-fg hover:bg-secondary hover:text-secondary-fg',\n          'aria-[current=page]:text-fg aria-[current=page]*:[svg]:text-fg',\n          'col-span-full grid grid-cols-[auto_1fr_1.5rem_0.5rem_auto] supports-[grid-template-columns:subgrid]:grid-cols-subgrid md:supports-[grid-template-columns:subgrid]:grid-cols-none',\n          'relative min-w-0 items-center gap-x-3 rounded-lg p-2 text-start font-medium text-base/6 md:gap-x-(--navbar-gutter) md:px-(--navbar-gutter) md:py-[calc(var(--navbar-gutter)---spacing(0.5))] md:text-sm/5',\n          '*:[svg]:size-5 *:[svg]:shrink-0 *:[svg]:text-muted-fg md:*:[svg]:size-4',\n          '*:data-[slot=loader]:size-5 *:data-[slot=loader]:shrink-0 md:*:data-[slot=loader]:size-4',\n          '*:not-nth-2:last:[svg]:row-start-1 *:not-nth-2:last:[svg]:ms-auto *:not-nth-2:last:[svg]:size-5 md:*:not-nth-2:last:[svg]:size-4',\n          '*:data-[slot=avatar]:-m-0.5 *:data-[slot=avatar]:size-6 md:*:data-[slot=avatar]:size-5',\n          '*:[svg]:text-muted-fg pressed:*:[svg]:text-fg hover:*:[svg]:text-fg',\n          'outline-hidden focus-visible:inset-ring focus-visible:inset-ring-ring focus-visible:ring-2 focus-visible:ring-ring/20',\n          'text-start disabled:cursor-default disabled:opacity-50',\n        ],\n        className\n      )}\n      {...props}\n    >\n      {(values) => (\n        <>\n          {typeof props.children === 'function' ? props.children(values) : props.children}\n\n          {(isCurrent || values.isCurrent) && (\n            <motion.span\n              data-slot=\"current-indicator\"\n              layoutId=\"current-indicator\"\n              transition={{ type: 'spring', stiffness: 500, damping: 40 }}\n              className={twJoin(\n                'absolute rounded-full bg-fg [--gutter:--spacing(0.5)]',\n                'inset-y-[calc(var(--navbar-gutter)---spacing(0.5))] -start-4 w-(--gutter) md:inset-y-auto md:w-auto',\n                'md:inset-x-2 md:-bottom-[calc(var(--navbar-gutter)+1px)] md:h-(--gutter)'\n              )}\n            />\n          )}\n        </>\n      )}\n    </Link>\n  )\n}\n\nconst NavbarSpacer = ({ className, ref, ...props }: React.ComponentProps<'div'>) => {\n  return <div ref={ref} className={twMerge('-ms-4 flex-1', className)} {...props} />\n}\n\nconst NavbarStart = ({ className, ref, ...props }: React.ComponentProps<'div'>) => {\n  return <div ref={ref} className={twMerge('relative p-2 py-4 md:p-0.5', className)} {...props} />\n}\n\nconst NavbarGap = ({ className, ref, ...props }: React.ComponentProps<'div'>) => {\n  return <div ref={ref} className={twMerge('mx-2', className)} {...props} />\n}\n\nconst NavbarSeparator = ({ className, ...props }: React.ComponentProps<typeof Separator>) => {\n  return <Separator orientation=\"vertical\" className={twMerge('h-5', className)} {...props} />\n}\n\nconst NavbarMobile = ({ className, ref, ...props }: React.ComponentProps<'div'>) => {\n  return (\n    <div\n      ref={ref}\n      data-slot=\"navbar-mobile\"\n      className={twMerge(\n        'group/navbar-mobile flex items-center gap-x-3 px-4 py-2.5 md:hidden',\n        'group-has-data-navbar-sticky/navbar:sticky group-has-data-navbar-sticky/navbar:bg-navbar',\n        // top\n        'group-has-data-navbar-sticky/navbar:group-has-placement-top/navbar:top-0 group-has-data-navbar-sticky/navbar:group-has-placement-top/navbar:border-b',\n        // bottom\n        'group-has-data-navbar-sticky/navbar:group-has-placement-bottom/navbar:bottom-0 group-has-data-navbar-sticky/navbar:group-has-placement-bottom/navbar:border-t',\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nconst NavbarInset = ({ className, ref, children, ...props }: React.ComponentProps<'div'>) => {\n  return (\n    <div\n      ref={ref}\n      data-navbar-inset={true}\n      className={twMerge('flex flex-1 flex-col bg-navbar pb-2 md:px-2 dark:bg-bg', className)}\n      {...props}\n    >\n      <div className=\"grow bg-bg p-6 md:rounded-lg md:p-16 md:shadow-xs md:ring-1 md:ring-fg/15 md:dark:bg-navbar md:dark:ring-border md:dark:group-has-data-navbar-inset/navbar:bg-muted\">\n        <div className=\"mx-auto max-w-7xl\">{children}</div>\n      </div>\n    </div>\n  )\n}\n\ninterface NavbarTriggerProps extends ButtonProps {\n  ref?: React.RefObject<HTMLButtonElement>\n}\n\nconst NavbarTrigger = ({ className, onPress, ref, ...props }: NavbarTriggerProps) => {\n  const { toggleNavbar } = useNavbar()\n  return (\n    <Button\n      ref={ref}\n      data-slot=\"navbar-trigger\"\n      intent=\"plain\"\n      aria-label={props['aria-label'] || 'Toggle Navbar'}\n      size=\"sq-sm\"\n      className={cx('-ms-2 lg:hidden', className)}\n      onPress={(event) => {\n        onPress?.(event)\n        toggleNavbar()\n      }}\n      {...props}\n    >\n      <Bars2Icon />\n      <span className=\"sr-only\">Toggle Navbar</span>\n    </Button>\n  )\n}\n\nconst NavbarLabel = ({ className, ...props }: React.ComponentProps<'span'>) => {\n  return (\n    <span\n      data-slot=\"navbar-label\"\n      className={twJoin('col-start-2 row-start-1 truncate', className)}\n      {...props}\n    />\n  )\n}\n\nexport type { NavbarItemProps, NavbarProps, NavbarProviderProps, NavbarTriggerProps }\nexport {\n  Navbar,\n  NavbarGap,\n  NavbarInset,\n  NavbarItem,\n  NavbarLabel,\n  NavbarMobile,\n  NavbarProvider,\n  NavbarSection,\n  NavbarSeparator,\n  NavbarSpacer,\n  NavbarStart,\n  NavbarTrigger,\n  useNavbar,\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}