{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "navbar", "title": "Navbar", "description": "Top navigation with logo, primary links, trailing actions, and profile dropdown.", "dependencies": [ "@radix-ui/react-dropdown-menu" ], "files": [ { "path": "registry/components/navbar/index.ts", "content": "export { Navbar } from \"./index.tsx\"\nexport { NAVBAR_ACCENT_HEX } from \"./types\"\nexport type {\n NavbarActionItem,\n NavbarHref,\n NavbarIconAction,\n NavbarImageAction,\n NavbarLinkItem,\n NavbarLogo,\n NavbarProfile,\n NavbarProfileMenuItem,\n NavbarProps,\n NavbarTextAction,\n} from \"./types\"\n", "type": "registry:block" }, { "path": "registry/components/navbar/index.tsx", "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { NavbarLogo } from \"./navbar-logo\";\nimport { NavbarNavItems } from \"./navbar-nav-items\";\nimport { NavbarProfileMenu } from \"./navbar-profile-menu\";\nimport { NavbarTrailingActions } from \"./navbar-trailing-actions\";\nimport type { NavbarProps } from \"./types\";\n\nimport {\n LAYOUT_NAVBAR_INNER_CLASSES,\n LAYOUT_NAVBAR_OUTER_CLASSES,\n} from \"@/lib/layout\";\nimport { cn } from \"@/lib/utils\";\n\nexport function Navbar({\n logo,\n navItems,\n profile,\n trailingActions,\n className,\n}: NavbarProps) {\n return (\n \n \n
\n \n \n
\n\n
\n \n \n
\n \n \n );\n}\n", "type": "registry:block" }, { "path": "lib/layout.ts", "content": "/**\n * Layout tokens for registry blocks. Consuming apps can replace this file\n * to match site-wide navbar shell (max width, gutters, etc.).\n */\nexport const LAYOUT_NAVBAR_OUTER_CLASSES = \"w-full\";\n\nexport const LAYOUT_NAVBAR_INNER_CLASSES =\n \"mx-auto flex w-full max-w-[1440px] flex-row items-center\";\n", "type": "registry:lib" }, { "path": "registry/components/navbar/types.ts", "content": "import type { MouseEventHandler, ReactNode } from \"react\"\n\n/** Hover + active text/icon color for primary nav and profile menu (keep Tailwind `text-[#6962AC]` in sync). */\nexport const NAVBAR_ACCENT_HEX = \"#6962AC\" as const\n\nexport type NavbarHref = string\n\nexport type NavbarLinkItem = {\n id?: string\n label: string\n href: NavbarHref\n /** When omitted, `http(s)://` URLs open in a new tab; app paths stay in the same tab. */\n openInNewTab?: boolean\n /**\n * Fires on the anchor click before navigation. Call `event.preventDefault()` to handle\n * routing or actions yourself (e.g. Next.js `router.push`).\n */\n onClick?: MouseEventHandler\n /**\n * Mark the current route (or logical section). Renders accent color and an underline;\n * set from the consuming app (e.g. compare `pathname` to `href`).\n */\n isActive?: boolean\n}\n\nexport type NavbarLogo = {\n src: string\n alt: string\n href: NavbarHref\n openInNewTab?: boolean\n /** Same as link items: optional handler on the logo anchor (e.g. `preventDefault` + client routing). */\n onClick?: MouseEventHandler\n}\n\nexport type NavbarProfileMenuItem = NavbarLinkItem & {\n /** Leading icon next to the label (treat as decorative when `label` is set). */\n icon?: ReactNode\n}\n\nexport type NavbarProfile = {\n avatarSrc?: string\n avatarAlt?: string\n /** Shown when there is no `avatarSrc` (typically initials). */\n fallbackText?: string\n menuItems: NavbarProfileMenuItem[]\n /** Accessible name for the profile menu trigger. */\n menuTriggerLabel?: string\n}\n\nexport type NavbarTextAction = {\n id?: string\n type: \"text\"\n label: string\n href: NavbarHref\n openInNewTab?: boolean\n onClick?: MouseEventHandler\n}\n\nexport type NavbarIconAction = {\n id?: string\n type: \"icon\"\n icon: ReactNode\n ariaLabel: string\n href: NavbarHref\n openInNewTab?: boolean\n onClick?: MouseEventHandler\n /** Shown as the native browser tooltip on hover (e.g. \"Calendar\"). */\n tooltip?: string\n /**\n * Optional unread / notification count. When greater than zero, a red pill is shown on the icon\n * (values above 9 display as `9+`).\n */\n notificationCount?: number\n}\n\nexport type NavbarImageAction = {\n id?: string\n type: \"image\"\n src: string\n alt: string\n href: NavbarHref\n openInNewTab?: boolean\n /** Optional classes for the `` (size, object-fit, etc.). */\n imageClassName?: string\n onClick?: MouseEventHandler\n /** Native tooltip on hover (e.g. \"Download app\"). */\n tooltip?: string\n}\n\nexport type NavbarActionItem = NavbarTextAction | NavbarIconAction | NavbarImageAction\n\nexport type NavbarProps = {\n logo: NavbarLogo\n navItems: NavbarLinkItem[]\n profile: NavbarProfile\n /** Shown to the left of the profile control (text links and/or icon buttons). */\n trailingActions?: NavbarActionItem[]\n className?: string\n}\n", "type": "registry:block" }, { "path": "registry/components/navbar/navbar-anchor.tsx", "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport type NavbarAnchorProps = Omit<\n React.AnchorHTMLAttributes,\n \"href\"\n> & {\n href: string\n openInNewTab?: boolean\n}\n\nfunction resolveOpenInNewTab(href: string, openInNewTab?: boolean) {\n if (typeof openInNewTab === \"boolean\") {\n return openInNewTab\n }\n\n return /^https?:\\/\\//i.test(href)\n}\n\nexport const NavbarAnchor = React.forwardRef(\n function NavbarAnchor(\n { href, openInNewTab, className, children, ...rest },\n ref,\n ) {\n const external = resolveOpenInNewTab(href, openInNewTab)\n\n return (\n \n {children}\n \n )\n },\n)\n\nNavbarAnchor.displayName = \"NavbarAnchor\"\n", "type": "registry:block" }, { "path": "registry/components/navbar/navbar-logo.tsx", "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { NavbarAnchor } from \"./navbar-anchor\"\nimport type { NavbarLogo as NavbarLogoConfig } from \"./types\"\n\ntype NavbarLogoProps = {\n logo: NavbarLogoConfig\n className?: string\n}\n\nexport function NavbarLogo({ logo, className }: NavbarLogoProps) {\n return (\n \n \n \n )\n}\n", "type": "registry:block" }, { "path": "registry/components/navbar/navbar-nav-items.tsx", "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { NavbarAnchor } from \"./navbar-anchor\"\nimport type { NavbarLinkItem } from \"./types\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype NavbarNavItemsProps = {\n items: Array\n className?: string\n}\n\nexport function NavbarNavItems({ items, className }: NavbarNavItemsProps) {\n if (!items.length) {\n return null\n }\n\n return (\n \n
    \n {items.map((item, index) => (\n
  • \n \n {item.label}\n \n
  • \n ))}\n
\n \n )\n}\n", "type": "registry:block" }, { "path": "registry/components/navbar/navbar-profile-menu.tsx", "content": "\"use client\";\n\nimport * as DropdownMenu from \"@radix-ui/react-dropdown-menu\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nimport { NavbarAnchor } from \"./navbar-anchor\";\nimport type { NavbarProfile } from \"./types\";\n\ntype NavbarProfileMenuProps = {\n profile: NavbarProfile;\n className?: string;\n};\n\nfunction initials(value: string) {\n const parts = value.trim().split(/\\s+/).filter(Boolean);\n if (!parts.length) {\n return \"?\";\n }\n\n if (parts.length === 1) {\n return parts[0].slice(0, 2).toUpperCase();\n }\n\n return `${parts[0][0] ?? \"\"}${parts[parts.length - 1][0] ?? \"\"}`.toUpperCase();\n}\n\nconst menuItemClassName =\n \"flex cursor-pointer select-none items-center gap-2 rounded-sm px-3 py-2 font-poppins text-[14px] font-medium leading-6 shadow-none outline-none transition-colors subpixel-antialiased text-gray-700 hover:text-[#6962AC] data-[highlighted]:text-[#6962AC] data-[highlighted]:shadow-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50\"\n\nconst menuContentClassName =\n \"z-[220] min-w-[200px] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md\";\n\nexport function NavbarProfileMenu({\n profile,\n className,\n}: NavbarProfileMenuProps) {\n const label =\n profile.menuTriggerLabel ??\n profile.avatarAlt ??\n profile.fallbackText ??\n \"Account menu\";\n\n return (\n
\n \n \n \n {profile.avatarSrc ? (\n \n ) : (\n \n {initials(profile.fallbackText ?? profile.avatarAlt ?? \"User\")}\n \n )}\n \n \n\n \n \n {profile.menuItems.length === 0 ? (\n
\n No menu items.\n
\n ) : (\n profile.menuItems.map((item, index) => (\n \n \n {item.icon ? (\n \n {item.icon}\n \n ) : null}\n \n {item.label}\n \n \n \n ))\n )}\n \n
\n
\n
\n );\n}\n", "type": "registry:block" }, { "path": "registry/components/navbar/navbar-trailing-actions.tsx", "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { NavbarAnchor } from \"./navbar-anchor\";\nimport type { NavbarActionItem } from \"./types\";\n\ntype NavbarTrailingActionsProps = {\n items: Array;\n className?: string;\n};\n\nexport function NavbarTrailingActions({\n items,\n className,\n}: NavbarTrailingActionsProps) {\n if (!items.length) {\n return null;\n }\n\n return (\n \n {items.map((item, index) => {\n const key = item.id ?? `${item.type}-${item.href}-${index}`;\n\n if (item.type === \"text\") {\n return (\n \n {item.label}\n \n );\n }\n\n if (item.type === \"image\") {\n const imageClassName = item.imageClassName?.trim().length\n ? item.imageClassName\n : \"size-8 max-h-9 object-contain\";\n\n return (\n \n \n \n );\n }\n\n const count =\n typeof item.notificationCount === \"number\" && item.notificationCount > 0\n ? item.notificationCount\n : 0;\n const badge =\n count > 0 ? (\n \n {count > 9 ? \"9+\" : count}\n \n ) : null;\n\n return (\n \n {item.icon}\n {badge}\n \n );\n })}\n \n );\n}\n", "type": "registry:block" } ], "type": "registry:block" }