{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"header-app-01","type":"registry:component","title":"Dashboard Header","description":"Clean dashboard header with search, notifications, and user menu. Features sticky positioning and mobile-responsive navigation.","dependencies":["lucide-react"],"registryDependencies":["avatar","badge","button","dropdown-menu","input"],"files":[{"path":"src/registry/blocks/application/navigation-layout/headers/header-app-01.tsx","content":"\"use client\";\n\nimport { Menu, Search, X } from \"lucide-react\";\nimport { useEffect, useState } from \"react\";\nimport {\n  Dropdown01,\n  Dropdown02,\n} from \"@/registry/blocks/application/interactive/dropdowns\";\nimport { cn } from \"@/registry/lib/utils\";\nimport { Button } from \"@/registry/ui/button\";\n\nimport {\n  CommandDialog,\n  CommandEmpty,\n  CommandGroup,\n  CommandInput,\n  CommandItem,\n  CommandList,\n  CommandSeparator,\n} from \"@/registry/ui/command\";\n\ninterface NavigationItem {\n  id: string;\n  label: string;\n  href: string;\n  isActive: boolean;\n}\n\nexport interface HeaderApp01Props {\n  className?: string;\n}\n\nconst content: {\n  brand: {\n    name: string;\n    logo: React.ReactNode;\n    href: string;\n  };\n  navigation: NavigationItem[];\n  search: {\n    placeholder: string;\n  };\n  commandItems: {\n    pages: { id: string; label: string; url: string }[];\n    settings: { id: string; label: string; action: string }[];\n    actions: { id: string; label: string; action: string }[];\n  };\n} = {\n  brand: {\n    name: \"Dashboard\",\n    logo: <div className=\"h-6 w-6 rounded bg-primary\" />,\n    href: \"/\",\n  },\n  navigation: [\n    { id: \"overview\", label: \"Overview\", href: \"/dashboard\", isActive: true },\n    {\n      id: \"analytics\",\n      label: \"Analytics\",\n      href: \"/analytics\",\n      isActive: false,\n    },\n    { id: \"reports\", label: \"Reports\", href: \"/reports\", isActive: false },\n    { id: \"settings\", label: \"Settings\", href: \"/settings\", isActive: false },\n  ],\n  search: {\n    placeholder: \"Search...\",\n  },\n  commandItems: {\n    pages: [\n      { id: \"dashboard\", label: \"Dashboard\", url: \"/dashboard\" },\n      { id: \"analytics\", label: \"Analytics\", url: \"/analytics\" },\n      { id: \"reports\", label: \"Reports\", url: \"/reports\" },\n      { id: \"team\", label: \"Team\", url: \"/team\" },\n      { id: \"projects\", label: \"Projects\", url: \"/projects\" },\n    ],\n    settings: [\n      { id: \"profile\", label: \"Profile Settings\", action: \"profile\" },\n      { id: \"preferences\", label: \"Preferences\", action: \"preferences\" },\n      { id: \"billing\", label: \"Billing\", action: \"billing\" },\n    ],\n    actions: [\n      { id: \"new-project\", label: \"Create New Project\", action: \"new-project\" },\n      { id: \"invite-user\", label: \"Invite User\", action: \"invite-user\" },\n      { id: \"export-data\", label: \"Export Data\", action: \"export-data\" },\n    ],\n  },\n};\n\nexport function HeaderApp01({ className }: HeaderApp01Props) {\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n  const [commandOpen, setCommandOpen] = useState(false);\n\n  const handleMobileMenuToggle = () => {\n    setMobileMenuOpen(!mobileMenuOpen);\n  };\n\n  const handleMobileMenuClose = () => {\n    setMobileMenuOpen(false);\n  };\n\n  const handleNavigationClick = (item: NavigationItem) => {\n    console.log(\"Navigation clicked:\", item.label);\n  };\n\n  const handleCommandClick = () => {\n    setCommandOpen(true);\n  };\n\n  const handleCommandItemSelect = (\n    value: string,\n    type: \"page\" | \"setting\" | \"action\",\n  ) => {\n    console.log(`Command ${type} selected:`, value);\n    setCommandOpen(false);\n  };\n\n  // Keyboard shortcut to open command palette\n  useEffect(() => {\n    const down = (e: KeyboardEvent) => {\n      if (e.key === \"k\" && (e.metaKey || e.ctrlKey)) {\n        e.preventDefault();\n        setCommandOpen((open) => !open);\n      }\n    };\n\n    document.addEventListener(\"keydown\", down);\n    return () => document.removeEventListener(\"keydown\", down);\n  }, []);\n\n  return (\n    <header\n      className={cn(\n        \"sticky top-0 z-50 w-full border-b border-border/40 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60\",\n        className,\n      )}\n      data-testid=\"header-app-01\"\n    >\n      <div className=\"container flex h-14 max-w-screen-2xl mx-auto items-center px-4 sm:px-6 lg:px-8\">\n        {/* Mobile menu button */}\n        <Button\n          variant=\"ghost\"\n          size=\"icon\"\n          className=\"mr-2 md:hidden\"\n          onClick={handleMobileMenuToggle}\n          data-testid=\"mobile-menu-trigger\"\n        >\n          <Menu className=\"h-4 w-4\" />\n          <span className=\"sr-only\">Toggle menu</span>\n        </Button>\n\n        {/* Logo */}\n        <div className=\"mr-2 sm:mr-4 flex\">\n          <a\n            href={content.brand.href}\n            className=\"mr-2 sm:mr-6 flex items-center space-x-2\"\n            data-testid=\"brand-link\"\n          >\n            {content.brand.logo}\n            <span className=\"hidden sm:inline-block font-bold\">\n              {content.brand.name}\n            </span>\n          </a>\n        </div>\n\n        {/* Navigation */}\n        <nav className=\"hidden lg:flex items-center space-x-4 xl:space-x-6 text-sm font-medium\">\n          {content.navigation.map((item) => (\n            <button\n              key={item.id}\n              type=\"button\"\n              className={cn(\n                \"transition-colors hover:text-foreground/80\",\n                item.isActive ? \"text-foreground\" : \"text-foreground/60\",\n              )}\n              onClick={() => handleNavigationClick(item)}\n              data-testid={`nav-item-${item.id}`}\n            >\n              {item.label}\n            </button>\n          ))}\n        </nav>\n\n        <div className=\"flex flex-1 items-center justify-between space-x-2 md:justify-end\">\n          {/* Search - Click to open command palette */}\n          <div className=\"w-full flex-1 md:w-auto md:flex-none\">\n            <Button\n              variant=\"outline\"\n              className=\"w-full sm:w-[200px] md:w-[300px] lg:w-[400px] justify-start text-muted-foreground bg-muted/50 hover:bg-muted\"\n              onClick={handleCommandClick}\n              data-testid=\"search-trigger\"\n            >\n              <Search className=\"h-4 w-4 mr-2\" />\n              <span className=\"hidden sm:inline\">\n                {content.search.placeholder}\n              </span>\n              <span className=\"sm:hidden\">Search...</span>\n              <div className=\"ml-auto hidden sm:flex items-center space-x-1\">\n                <kbd className=\"pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100\">\n                  <span className=\"text-xs\">⌘</span>K\n                </kbd>\n              </div>\n            </Button>\n          </div>\n\n          {/* Actions */}\n          <div\n            className=\"flex items-center space-x-1 sm:space-x-2\"\n            data-testid=\"header-actions\"\n          >\n            {/* Notifications */}\n            <Dropdown02 />\n\n            {/* User menu */}\n            <Dropdown01 />\n          </div>\n        </div>\n      </div>\n\n      {mobileMenuOpen && (\n        <div\n          className=\"fixed inset-0 z-50 md:hidden\"\n          data-testid=\"mobile-menu-overlay\"\n        >\n          <div\n            role=\"button\"\n            tabIndex={0}\n            className=\"fixed inset-0 bg-background/80 backdrop-blur-sm\"\n            onClick={handleMobileMenuClose}\n            onKeyDown={(e) => {\n              if (e.key === \"Enter\" || e.key === \" \") {\n                handleMobileMenuClose();\n              }\n            }}\n          />\n          <div className=\"fixed top-0 left-0 h-full w-64 bg-background border-r border-border shadow-lg\">\n            <div className=\"flex items-center justify-between p-4 border-b border-border\">\n              <div className=\"flex items-center space-x-2\">\n                {content.brand.logo}\n                <span className=\"font-bold\">{content.brand.name}</span>\n              </div>\n              <Button\n                variant=\"ghost\"\n                size=\"icon\"\n                onClick={handleMobileMenuClose}\n                data-testid=\"mobile-menu-close\"\n              >\n                <X className=\"h-4 w-4\" />\n              </Button>\n            </div>\n            <nav className=\"p-4 space-y-2\" data-testid=\"mobile-navigation\">\n              {content.navigation.map((item) => (\n                <button\n                  key={item.id}\n                  type=\"button\"\n                  onClick={() => handleNavigationClick(item)}\n                  className={cn(\n                    \"block w-full text-left px-3 py-2 rounded-md text-sm font-medium\",\n                    item.isActive\n                      ? \"bg-muted text-foreground\"\n                      : \"text-muted-foreground hover:text-foreground hover:bg-muted/50\",\n                  )}\n                  data-testid={`mobile-nav-item-${item.id}`}\n                >\n                  {item.label}\n                </button>\n              ))}\n            </nav>\n          </div>\n        </div>\n      )}\n\n      {/* Command Dialog */}\n      <CommandDialog\n        open={commandOpen}\n        onOpenChange={setCommandOpen}\n        title=\"Search Dashboard\"\n        description=\"Quickly navigate to pages, settings, or perform actions\"\n      >\n        <CommandInput\n          placeholder=\"Type a command or search...\"\n          data-testid=\"command-input\"\n        />\n        <CommandList>\n          <CommandEmpty>No results found.</CommandEmpty>\n\n          <CommandGroup heading=\"Pages\">\n            {content.commandItems.pages.map((page) => (\n              <CommandItem\n                key={page.id}\n                value={page.label}\n                onSelect={() => handleCommandItemSelect(page.id, \"page\")}\n                data-testid={`command-page-${page.id}`}\n              >\n                <span>{page.label}</span>\n              </CommandItem>\n            ))}\n          </CommandGroup>\n\n          <CommandSeparator />\n\n          <CommandGroup heading=\"Settings\">\n            {content.commandItems.settings.map((setting) => (\n              <CommandItem\n                key={setting.id}\n                value={setting.label}\n                onSelect={() => handleCommandItemSelect(setting.id, \"setting\")}\n                data-testid={`command-setting-${setting.id}`}\n              >\n                <span>{setting.label}</span>\n              </CommandItem>\n            ))}\n          </CommandGroup>\n\n          <CommandSeparator />\n\n          <CommandGroup heading=\"Actions\">\n            {content.commandItems.actions.map((action) => (\n              <CommandItem\n                key={action.id}\n                value={action.label}\n                onSelect={() => handleCommandItemSelect(action.id, \"action\")}\n                data-testid={`command-action-${action.id}`}\n              >\n                <span>{action.label}</span>\n              </CommandItem>\n            ))}\n          </CommandGroup>\n        </CommandList>\n      </CommandDialog>\n    </header>\n  );\n}\n","type":"registry:component"},{"path":"src/registry/lib/utils.ts","content":"import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n","type":"registry:lib"}]}