{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "app-sidebar",
  "title": "App Sidebar",
  "description": "A config-driven application sidebar with main navigation, projects, secondary links, and a user menu.",
  "registryDependencies": [
    "@hoogin/sidebar",
    "avatar",
    "collapsible",
    "dropdown-menu"
  ],
  "files": [
    {
      "path": "registry/ui/app-sidebar.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { NavMain } from \"@/hoogin/ui/nav-main\"\nimport { NavProjects } from \"@/hoogin/ui/nav-projects\"\nimport { NavSecondary } from \"@/hoogin/ui/nav-secondary\"\nimport { NavUser } from \"@/hoogin/ui/nav-user\"\nimport type {\n  SidebarBrand,\n  SidebarMore,\n  SidebarNavItem,\n  SidebarProject,\n  SidebarSecondaryItem,\n  SidebarUser,\n  SidebarUserMenu,\n} from \"@/hoogin/ui/sidebar.types\"\nimport {\n  Sidebar,\n  SidebarContent,\n  SidebarFooter,\n  SidebarHeader,\n  SidebarMenu,\n  SidebarMenuButton,\n  SidebarMenuItem,\n} from \"@/hoogin/ui/sidebar\"\nimport { BlocksIcon } from \"lucide-react\"\n\ntype AppSidebarProps = React.ComponentProps<typeof Sidebar> & {\n  brand: SidebarBrand\n  user?: SidebarUser\n  dataMain: SidebarNavItem[]\n  dataSecondary?: SidebarSecondaryItem[]\n  dataProjects?: SidebarProject[]\n  dataMainLabel?: string\n  dataProjectsLabel?: string\n  dataProjectsMore?: SidebarMore\n  dataUserMenu?: SidebarUserMenu\n}\n\nexport function AppSidebar({\n  brand,\n  user,\n  dataMain,\n  dataSecondary,\n  dataProjects,\n  dataMainLabel,\n  dataProjectsLabel,\n  dataProjectsMore,\n  dataUserMenu,\n  ...props\n}: AppSidebarProps) {\n  return (\n    <Sidebar variant=\"inset\" {...props}>\n      <SidebarHeader>\n        <SidebarMenu>\n          <SidebarMenuItem>\n            <SidebarMenuButton size=\"lg\" render={<a href=\"#\" />}>\n              <div className=\"flex aspect-square size-8 items-center justify-center\">\n                {typeof brand.logo === \"string\" ? (\n                  <img src={brand.logo} alt={brand.name} className=\"size-8\" />\n                ) : brand.logo ? (\n                  brand.logo\n                ) : (\n                  <BlocksIcon className=\"size-4\" />\n                )}\n              </div>\n              <div className=\"grid flex-1 text-left text-sm leading-tight\">\n                <span className=\"truncate font-medium\">{brand.name}</span>\n                {brand.description ? (\n                  <span className=\"truncate text-xs\">{brand.description}</span>\n                ) : null}\n              </div>\n            </SidebarMenuButton>\n          </SidebarMenuItem>\n        </SidebarMenu>\n      </SidebarHeader>\n      <SidebarContent>\n        <NavMain items={dataMain} label={dataMainLabel} />\n        {dataProjects?.length ? (\n          <NavProjects\n            projects={dataProjects}\n            label={dataProjectsLabel}\n            more={dataProjectsMore}\n          />\n        ) : null}\n        {dataSecondary?.length ? (\n          <NavSecondary items={dataSecondary} className=\"mt-auto\" />\n        ) : null}\n      </SidebarContent>\n      {user ? (\n        <SidebarFooter>\n          <NavUser user={user} menu={dataUserMenu} />\n        </SidebarFooter>\n      ) : null}\n    </Sidebar>\n  )\n}\n",
      "type": "registry:ui",
      "target": "hoogin/ui/app-sidebar.tsx"
    },
    {
      "path": "registry/ui/nav-main.tsx",
      "content": "import {\n  Collapsible,\n  CollapsibleContent,\n  CollapsibleTrigger,\n} from \"@/components/ui/collapsible\"\nimport {\n  SidebarGroup,\n  SidebarGroupLabel,\n  SidebarMenu,\n  SidebarMenuAction,\n  SidebarMenuButton,\n  SidebarMenuItem,\n  SidebarMenuSub,\n  SidebarMenuSubButton,\n  SidebarMenuSubItem,\n} from \"@/hoogin/ui/sidebar\"\nimport { ChevronRightIcon } from \"lucide-react\"\nimport { Link, useMatches } from \"@tanstack/react-router\"\nimport type {\n  SidebarNavItem,\n  SidebarNavSubItem,\n} from \"@/hoogin/ui/sidebar.types\"\n\nfunction isSubItemActive(sub: SidebarNavSubItem, fullPath: string): boolean {\n  if (sub.url === fullPath) return true\n  return sub.items?.some((child) => isSubItemActive(child, fullPath)) ?? false\n}\n\nfunction NavSubItem({\n  sub,\n  fullPath,\n}: {\n  sub: SidebarNavSubItem\n  fullPath: string\n}) {\n  const active = isSubItemActive(sub, fullPath)\n  if (!sub.items?.length) {\n    return (\n      <SidebarMenuSubItem>\n        <SidebarMenuSubButton isActive={active} render={<Link to={sub.url} />}>\n          <span>{sub.title}</span>\n        </SidebarMenuSubButton>\n      </SidebarMenuSubItem>\n    )\n  }\n\n  return (\n    <Collapsible\n      defaultOpen={active}\n      render={<SidebarMenuSubItem />}\n    >\n      <SidebarMenuSubButton\n        isActive={active}\n        className=\"pr-6\"\n        render={<Link to={sub.url} />}\n      >\n        <span>{sub.title}</span>\n      </SidebarMenuSubButton>\n      <CollapsibleTrigger\n        render={\n          <SidebarMenuAction className=\"aria-expanded:rotate-90\" />\n        }\n      >\n        <ChevronRightIcon />\n        <span className=\"sr-only\">Toggle</span>\n      </CollapsibleTrigger>\n      <CollapsibleContent>\n        <SidebarMenuSub>\n          {sub.items.map((child) => (\n            <NavSubItem key={child.title} sub={child} fullPath={fullPath} />\n          ))}\n        </SidebarMenuSub>\n      </CollapsibleContent>\n    </Collapsible>\n  )\n}\n\nexport function NavMain({\n  items,\n  label = \"Platform\",\n}: {\n  items: SidebarNavItem[]\n  label?: string\n}) {\n  const matches = useMatches()\n  const fullPath = matches[matches.length - 1]?.fullPath ?? \"\"\n  if (items.length === 0) {\n    return null\n  }\n\n  const isItemActive = (item: SidebarNavItem) => {\n    if (item.isActive) return true\n    if (item.url === fullPath) return true\n    return item.items?.some((sub) => isSubItemActive(sub, fullPath)) ?? false\n  }\n\n  return (\n    <SidebarGroup>\n      <SidebarGroupLabel>{label}</SidebarGroupLabel>\n      <SidebarMenu>\n        {items.map((item) => {\n          const active = isItemActive(item)\n          return (\n            <Collapsible\n              key={item.title}\n              defaultOpen={active}\n              render={<SidebarMenuItem />}\n            >\n              <SidebarMenuButton\n                tooltip={item.title}\n                render={<Link to={item.url} />}\n              >\n                <item.icon />\n                <span>{item.title}</span>\n              </SidebarMenuButton>\n              {item.items?.length ? (\n                <>\n                  <CollapsibleTrigger\n                    render={\n                      <SidebarMenuAction className=\"aria-expanded:rotate-90\" />\n                    }\n                  >\n                    <ChevronRightIcon />\n                    <span className=\"sr-only\">Toggle</span>\n                  </CollapsibleTrigger>\n                  <CollapsibleContent>\n                    <SidebarMenuSub>\n                      {item.items.map((sub) => (\n                        <NavSubItem\n                          key={sub.title}\n                          sub={sub}\n                          fullPath={fullPath}\n                        />\n                      ))}\n                    </SidebarMenuSub>\n                  </CollapsibleContent>\n                </>\n              ) : null}\n            </Collapsible>\n          )\n        })}\n      </SidebarMenu>\n    </SidebarGroup>\n  )\n}\n",
      "type": "registry:ui",
      "target": "hoogin/ui/nav-main.tsx"
    },
    {
      "path": "registry/ui/nav-projects.tsx",
      "content": "\"use client\"\n\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\"\nimport {\n  SidebarGroup,\n  SidebarGroupLabel,\n  SidebarMenu,\n  SidebarMenuAction,\n  SidebarMenuButton,\n  SidebarMenuItem,\n  useSidebar,\n} from \"@/hoogin/ui/sidebar\"\nimport { MoreHorizontalIcon, FolderIcon, ShareIcon, Trash2Icon } from \"lucide-react\"\nimport type {\n  SidebarMore,\n  SidebarProject,\n} from \"@/hoogin/ui/sidebar.types\"\n\nexport function NavProjects({\n  projects,\n  label = \"Projects\",\n  more,\n}: {\n  projects: SidebarProject[]\n  label?: string\n  more?: SidebarMore\n}) {\n  const { isMobile } = useSidebar()\n\n  if (projects.length === 0) {\n    return null\n  }\n\n  return (\n    <SidebarGroup className=\"group-data-[collapsible=icon]:hidden\">\n      <SidebarGroupLabel>{label}</SidebarGroupLabel>\n      <SidebarMenu>\n        {projects.map((item) => (\n          <SidebarMenuItem key={item.name}>\n            <SidebarMenuButton render={<a href={item.url} />}>\n              <item.icon />\n              <span>{item.name}</span>\n            </SidebarMenuButton>\n            <DropdownMenu>\n              <DropdownMenuTrigger\n                render={\n                  <SidebarMenuAction\n                    showOnHover\n                    className=\"aria-expanded:bg-muted\"\n                  />\n                }\n              >\n                <MoreHorizontalIcon\n                />\n                <span className=\"sr-only\">More</span>\n              </DropdownMenuTrigger>\n              <DropdownMenuContent\n                className=\"w-48\"\n                side={isMobile ? \"bottom\" : \"right\"}\n                align={isMobile ? \"end\" : \"start\"}\n              >\n                <DropdownMenuItem>\n                  <FolderIcon className=\"text-muted-foreground\" />\n                  <span>View Project</span>\n                </DropdownMenuItem>\n                <DropdownMenuItem>\n                  <ShareIcon className=\"text-muted-foreground\" />\n                  <span>Share Project</span>\n                </DropdownMenuItem>\n                <DropdownMenuSeparator />\n                <DropdownMenuItem>\n                  <Trash2Icon className=\"text-muted-foreground\" />\n                  <span>Delete Project</span>\n                </DropdownMenuItem>\n              </DropdownMenuContent>\n            </DropdownMenu>\n          </SidebarMenuItem>\n        ))}\n        {more ? (\n          <SidebarMenuItem>\n            <SidebarMenuButton render={<a href={more.url} />}>\n              <MoreHorizontalIcon\n              />\n              <span>{more.label}</span>\n            </SidebarMenuButton>\n          </SidebarMenuItem>\n        ) : null}\n      </SidebarMenu>\n    </SidebarGroup>\n  )\n}\n",
      "type": "registry:ui",
      "target": "hoogin/ui/nav-projects.tsx"
    },
    {
      "path": "registry/ui/nav-secondary.tsx",
      "content": "import * as React from \"react\"\n\nimport {\n  SidebarGroup,\n  SidebarGroupContent,\n  SidebarMenu,\n  SidebarMenuButton,\n  SidebarMenuItem,\n} from \"@/hoogin/ui/sidebar\"\nimport type { SidebarSecondaryItem } from \"@/hoogin/ui/sidebar.types\"\n\nexport function NavSecondary({\n  items,\n  ...props\n}: {\n  items: SidebarSecondaryItem[]\n} & React.ComponentPropsWithoutRef<typeof SidebarGroup>) {\n  return (\n    <SidebarGroup {...props}>\n      <SidebarGroupContent>\n        <SidebarMenu>\n          {items.map((item) => (\n            <SidebarMenuItem key={item.title}>\n              <SidebarMenuButton size=\"sm\" render={<a href={item.url} />}>\n                <item.icon />\n                <span>{item.title}</span>\n              </SidebarMenuButton>\n            </SidebarMenuItem>\n          ))}\n        </SidebarMenu>\n      </SidebarGroupContent>\n    </SidebarGroup>\n  )\n}\n",
      "type": "registry:ui",
      "target": "hoogin/ui/nav-secondary.tsx"
    },
    {
      "path": "registry/ui/nav-user.tsx",
      "content": "\"use client\"\n\nimport { Fragment } from \"react\"\n\nimport {\n  Avatar,\n  AvatarFallback,\n  AvatarImage,\n} from \"@/components/ui/avatar\"\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\"\nimport {\n  SidebarMenu,\n  SidebarMenuButton,\n  SidebarMenuItem,\n  useSidebar,\n} from \"@/hoogin/ui/sidebar\"\nimport { ChevronsUpDownIcon } from \"lucide-react\"\nimport type {\n  SidebarUser,\n  SidebarUserMenu,\n} from \"@/hoogin/ui/sidebar.types\"\n\nexport function NavUser({\n  user,\n  menu = [],\n}: {\n  user: SidebarUser\n  menu?: SidebarUserMenu\n}) {\n  const { isMobile } = useSidebar()\n  return (\n    <SidebarMenu>\n      <SidebarMenuItem>\n        <DropdownMenu>\n          <DropdownMenuTrigger\n            render={\n              <SidebarMenuButton size=\"lg\" className=\"aria-expanded:bg-muted\" />\n            }\n          >\n            <Avatar>\n              <AvatarImage src={user.avatar} alt={user.name} />\n              <AvatarFallback>CN</AvatarFallback>\n            </Avatar>\n            <div className=\"grid flex-1 text-left text-sm leading-tight\">\n              <span className=\"truncate font-medium\">{user.name}</span>\n              <span className=\"truncate text-xs\">{user.email}</span>\n            </div>\n            <ChevronsUpDownIcon className=\"ml-auto size-4\" />\n          </DropdownMenuTrigger>\n          <DropdownMenuContent\n            className=\"min-w-56 rounded-lg\"\n            side={isMobile ? \"bottom\" : \"right\"}\n            align=\"end\"\n            sideOffset={4}\n          >\n            <DropdownMenuGroup>\n              <DropdownMenuLabel className=\"p-0 font-normal\">\n                <div className=\"flex items-center gap-2 px-1 py-1.5 text-left text-sm\">\n                  <Avatar>\n                    <AvatarImage src={user.avatar} alt={user.name} />\n                    <AvatarFallback>CN</AvatarFallback>\n                  </Avatar>\n                  <div className=\"grid flex-1 text-left text-sm leading-tight\">\n                    <span className=\"truncate font-medium\">{user.name}</span>\n                    <span className=\"truncate text-xs\">{user.email}</span>\n                  </div>\n                </div>\n              </DropdownMenuLabel>\n            </DropdownMenuGroup>\n            {menu.map((group, index) => (\n              <Fragment key={index}>\n                <DropdownMenuSeparator />\n                <DropdownMenuGroup>\n                  {group.items.map((item) => (\n                    <DropdownMenuItem\n                      key={item.label}\n                      render={<a href={item.url} />}\n                    >\n                      {item.icon ? <item.icon /> : null}\n                      {item.label}\n                    </DropdownMenuItem>\n                  ))}\n                </DropdownMenuGroup>\n              </Fragment>\n            ))}\n          </DropdownMenuContent>\n        </DropdownMenu>\n      </SidebarMenuItem>\n    </SidebarMenu>\n  )\n}\n",
      "type": "registry:ui",
      "target": "hoogin/ui/nav-user.tsx"
    },
    {
      "path": "registry/ui/sidebar.types.ts",
      "content": "import { type LucideIcon } from \"lucide-react\"\nimport { type ReactNode } from \"react\"\n\nexport type SidebarBrand = {\n  name: string\n  description?: string\n  logo?: ReactNode\n}\n\nexport type SidebarUser = {\n  name: string\n  email: string\n  avatar: string\n}\n\nexport type SidebarNavSubItem = {\n  title: string\n  url: string\n  items?: SidebarNavSubItem[]\n}\n\nexport type SidebarNavItem = {\n  title: string\n  url: string\n  icon: LucideIcon\n  isActive?: boolean\n  items?: SidebarNavSubItem[]\n}\n\nexport type SidebarSecondaryItem = {\n  title: string\n  url: string\n  icon: LucideIcon\n}\n\nexport type SidebarProject = {\n  name: string\n  url: string\n  icon: LucideIcon\n}\n\nexport type SidebarMore = {\n  label: string\n  url: string\n}\n\nexport type SidebarUserMenuItem = {\n  label: string\n  url: string\n  icon?: LucideIcon\n}\n\nexport type SidebarUserMenuGroup = {\n  items: SidebarUserMenuItem[]\n}\n\nexport type SidebarUserMenu = SidebarUserMenuGroup[]\n",
      "type": "registry:file",
      "target": "hoogin/ui/sidebar.types.ts"
    }
  ],
  "type": "registry:ui"
}