{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sidebar-05",
  "type": "registry:block",
  "title": "Sidebar Double-Sided",
  "description": "A sidebar double-sided block.",
  "author": "ephraim duncan <https://ephraimduncan.com>",
  "registryDependencies": [
    "avatar",
    "dropdown-menu",
    "sidebar"
  ],
  "dependencies": [
    "@tabler/icons-react",
    "lucide-react"
  ],
  "files": [
    {
      "path": "content/components/sidebar/sidebar-05/app-sidebar.tsx",
      "type": "registry:component",
      "target": "components/sidebar-05/app-sidebar.tsx",
      "content": "'use client';\n\nimport {\n  IconActivityHeartbeat,\n  IconArchive,\n  IconBackground,\n  IconBellRinging,\n  IconBrandGoogle,\n  IconBrandMeta,\n  IconBrandNpm,\n  IconBrandOpenai,\n  IconBug,\n  IconChartBar,\n  IconChevronRight,\n  IconCloud,\n  IconDatabase,\n  IconFileText,\n  IconFolder,\n  IconFolders,\n  IconGitCommit,\n  IconGitMerge,\n  IconGitPullRequest,\n  IconHome,\n  IconKey,\n  IconLockExclamation,\n  IconLockPassword,\n  IconLogout,\n  IconNorthStar,\n  IconPackageExport,\n  IconPackages,\n  IconPasswordFingerprint,\n  IconPlayerPlay,\n  IconScanEye,\n  IconSettings,\n  IconShieldLock,\n  IconStar,\n  IconTarget,\n  IconTerminal2,\n  IconUser,\n  IconUserPlus,\n  IconWebhook,\n  IconX,\n} from '@tabler/icons-react';\nimport type React from 'react';\nimport { useState } from 'react';\nimport { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';\nimport {\n  Sidebar,\n  SidebarContent,\n  SidebarFooter,\n  SidebarGroup,\n  SidebarGroupContent,\n  SidebarHeader,\n  SidebarMenu,\n  SidebarMenuBadge,\n  SidebarMenuButton,\n  SidebarMenuItem,\n} from '@/components/ui/sidebar';\nimport { cn } from '@/lib/utils';\nimport { TeamSwitcher } from '@/components/sidebar-05/team-switcher';\n\nconst data = {\n  teams: [\n    {\n      name: 'OpenAI',\n      logo: IconBrandOpenai,\n      plan: 'Enterprise',\n    },\n    {\n      name: 'Anthropic',\n      logo: IconNorthStar,\n      plan: 'Pro',\n    },\n    {\n      name: 'Google',\n      logo: IconBrandGoogle,\n      plan: 'Free',\n    },\n    {\n      name: 'Meta',\n      logo: IconBrandMeta,\n      plan: 'Free',\n    },\n  ],\n};\n\ninterface SidebarItem {\n  id: string;\n  label: string;\n  icon: React.ComponentType<{ className?: string }>;\n  badge?: string;\n  hasSubItems?: boolean;\n  route?: string;\n  subItems?: {\n    id: string;\n    label: string;\n    icon: React.ComponentType<{ className?: string }>;\n    description?: string;\n    route?: string;\n  }[];\n}\n\nconst sidebarItems: SidebarItem[] = [\n  {\n    id: 'overview',\n    label: 'Overview',\n    icon: IconHome,\n    hasSubItems: true,\n    subItems: [\n      {\n        id: 'dashboard',\n        label: 'Dashboard',\n        icon: IconChartBar,\n        description: 'Project overview and activity',\n        route: '/overview/dashboard',\n      },\n      {\n        id: 'activity',\n        label: 'Activity',\n        icon: IconActivityHeartbeat,\n        description: 'Recent commits and changes',\n        route: '/overview/activity',\n      },\n      {\n        id: 'insights',\n        label: 'Insights',\n        icon: IconTarget,\n        description: 'Code analytics and metrics',\n        route: '/overview/insights',\n      },\n    ],\n  },\n  {\n    id: 'repositories',\n    label: 'Repositories',\n    icon: IconFolders,\n    badge: '12',\n    hasSubItems: true,\n    subItems: [\n      {\n        id: 'all-repos',\n        label: 'All Repositories',\n        icon: IconFolder,\n        description: 'Browse all your repositories',\n        route: '/repositories',\n      },\n      {\n        id: 'starred',\n        label: 'Starred',\n        icon: IconStar,\n        description: 'Your starred repositories',\n        route: '/repositories/starred',\n      },\n      {\n        id: 'archived',\n        label: 'Archived',\n        icon: IconArchive,\n        description: 'Archived repositories',\n        route: '/repositories/archived',\n      },\n    ],\n  },\n  {\n    id: 'pull-requests',\n    label: 'Pull Requests',\n    icon: IconGitPullRequest,\n    badge: '3',\n    hasSubItems: true,\n    subItems: [\n      {\n        id: 'open-prs',\n        label: 'Open',\n        icon: IconGitPullRequest,\n        description: 'Open pull requests',\n        route: '/pull-requests/open',\n      },\n      {\n        id: 'review-requests',\n        label: 'Review Requests',\n        icon: IconScanEye,\n        description: 'PRs awaiting your review',\n        route: '/pull-requests/review',\n      },\n      {\n        id: 'merged',\n        label: 'Merged',\n        icon: IconGitMerge,\n        description: 'Recently merged PRs',\n        route: '/pull-requests/merged',\n      },\n    ],\n  },\n  {\n    id: 'issues',\n    label: 'Issues',\n    icon: IconBug,\n    badge: '7',\n    hasSubItems: true,\n    subItems: [\n      {\n        id: 'open-issues',\n        label: 'Open Issues',\n        icon: IconBug,\n        description: 'Active issues and bugs',\n        route: '/issues/open',\n      },\n      {\n        id: 'assigned',\n        label: 'Assigned to Me',\n        icon: IconUserPlus,\n        description: 'Issues assigned to you',\n        route: '/issues/assigned',\n      },\n      {\n        id: 'created',\n        label: 'Created by Me',\n        icon: IconGitCommit,\n        description: \"Issues you've created\",\n        route: '/issues/created',\n      },\n    ],\n  },\n  {\n    id: 'actions',\n    label: 'Actions',\n    icon: IconBackground,\n    hasSubItems: true,\n    subItems: [\n      {\n        id: 'workflows',\n        label: 'Workflows',\n        icon: IconPlayerPlay,\n        description: 'CI/CD workflows and pipelines',\n        route: '/actions/workflows',\n      },\n      {\n        id: 'runners',\n        label: 'Runners',\n        icon: IconTerminal2,\n        description: 'Self-hosted runners',\n        route: '/actions/runners',\n      },\n      {\n        id: 'deployments',\n        label: 'Deployments',\n        icon: IconCloud,\n        description: 'Deployment history',\n        route: '/actions/deployments',\n      },\n    ],\n  },\n  {\n    id: 'packages',\n    label: 'Packages',\n    icon: IconPackages,\n    hasSubItems: true,\n    subItems: [\n      {\n        id: 'published',\n        label: 'Published',\n        icon: IconPackageExport,\n        description: 'Your published packages',\n        route: '/packages/published',\n      },\n      {\n        id: 'container-registry',\n        label: 'Container Registry',\n        icon: IconDatabase,\n        description: 'Docker images and containers',\n        route: '/packages/containers',\n      },\n      {\n        id: 'npm-packages',\n        label: 'npm Packages',\n        icon: IconBrandNpm,\n        description: 'Node.js packages',\n        route: '/packages/npm',\n      },\n    ],\n  },\n  {\n    id: 'security',\n    label: 'Security',\n    icon: IconLockPassword,\n    badge: '2',\n    hasSubItems: true,\n    subItems: [\n      {\n        id: 'alerts',\n        label: 'Security Alerts',\n        icon: IconLockExclamation,\n        description: 'Vulnerability alerts',\n        route: '/security/alerts',\n      },\n      {\n        id: 'advisories',\n        label: 'Advisories',\n        icon: IconShieldLock,\n        description: 'Security advisories',\n        route: '/security/advisories',\n      },\n      {\n        id: 'secrets',\n        label: 'Secrets',\n        icon: IconPasswordFingerprint,\n        description: 'Repository secrets',\n        route: '/security/secrets',\n      },\n    ],\n  },\n  {\n    id: 'settings',\n    label: 'Settings',\n    icon: IconSettings,\n    hasSubItems: true,\n    subItems: [\n      {\n        id: 'profile',\n        label: 'Profile',\n        icon: IconUser,\n        description: 'Your profile settings',\n        route: '/settings/profile',\n      },\n      {\n        id: 'notifications',\n        label: 'Notifications',\n        icon: IconBellRinging,\n        description: 'Notification preferences',\n        route: '/settings/notifications',\n      },\n      {\n        id: 'webhooks',\n        label: 'Webhooks',\n        icon: IconWebhook,\n        description: 'Webhook configurations',\n        route: '/settings/webhooks',\n      },\n      {\n        id: 'api-keys',\n        label: 'API Keys',\n        icon: IconKey,\n        description: 'Personal access tokens',\n        route: '/settings/api-keys',\n      },\n    ],\n  },\n  {\n    id: 'docs',\n    label: 'Documentation',\n    icon: IconFileText,\n    hasSubItems: false,\n    route: '/docs',\n  },\n];\n\nexport function AppSidebar() {\n  const [activeItem, setActiveItem] = useState<string | null>('overview');\n  const [selectedSubItem, setSelectedSubItem] = useState<string | null>(null);\n\n  const activeItemData = sidebarItems.find((item) => item.id === activeItem);\n\n  const handleItemClick = (item: SidebarItem) => {\n    if (item.hasSubItems) {\n      const isActive = activeItem === item.id;\n      setActiveItem(isActive ? null : item.id);\n      if (isActive) {\n        setSelectedSubItem(null);\n      }\n    } else {\n      if (activeItem) {\n        setActiveItem(null);\n        setSelectedSubItem(null);\n      }\n      console.log(`[v0] Navigating to: ${item.route}`);\n    }\n  };\n\n  const handleSubItemClick = (subItem: { id: string; route?: string }) => {\n    setSelectedSubItem(selectedSubItem === subItem.id ? null : subItem.id);\n    if (subItem.route) {\n      console.log(`[v0] Navigating to: ${subItem.route}`);\n    }\n  };\n\n  return (\n    <div className=\"flex h-dvh bg-background\">\n      <Sidebar\n        className=\"w-64 border-r\"\n        collapsible=\"none\"\n        side=\"left\"\n        variant=\"sidebar\"\n      >\n        <SidebarHeader>\n          <TeamSwitcher teams={data.teams} />\n        </SidebarHeader>\n\n        <SidebarContent>\n          <SidebarGroup>\n            <SidebarGroupContent>\n              <SidebarMenu>\n                {sidebarItems.map((item) => {\n                  const Icon = item.icon;\n                  const isActive = activeItem === item.id;\n                  const chevronIndicator = (\n                    <IconChevronRight\n                      className={cn(\n                        'h-4 w-4 shrink-0 transition-transform',\n                        isActive && 'rotate-90'\n                      )}\n                    />\n                  );\n\n                  return (\n                    <SidebarMenuItem key={item.id}>\n                      <SidebarMenuButton\n                        className=\"h-10 w-full px-3\"\n                        isActive={isActive}\n                        onClick={() => handleItemClick(item)}\n                      >\n                        <div className=\"flex min-w-0 flex-1 items-center gap-3\">\n                          <Icon className=\"h-4 w-4 shrink-0\" />\n                          <span className=\"truncate\">{item.label}</span>\n                        </div>\n                        <div className=\"ml-auto flex min-w-fit shrink-0 items-center gap-1\">\n                          {(item.badge || item.hasSubItems) &&\n                            (item.badge ? (\n                              <SidebarMenuBadge\n                                className={cn(\n                                  'min-w-fit',\n                                  item.hasSubItems && 'gap-x-3'\n                                )}\n                              >\n                                {item.badge}\n                                {item.hasSubItems && chevronIndicator}\n                              </SidebarMenuBadge>\n                            ) : (\n                              chevronIndicator\n                            ))}\n                        </div>\n                      </SidebarMenuButton>\n                    </SidebarMenuItem>\n                  );\n                })}\n              </SidebarMenu>\n            </SidebarGroupContent>\n          </SidebarGroup>\n        </SidebarContent>\n\n        <SidebarFooter>\n          <SidebarMenu>\n            <SidebarMenuItem>\n              <SidebarMenuButton className=\"h-12 w-full px-3\">\n                <div className=\"flex min-w-0 flex-1 items-center gap-3\">\n                  <Avatar className=\"h-8 w-8 rounded-full\">\n                    <AvatarImage alt=\"ephraim\" src=\"/avatar-01.png\" />\n                    <AvatarFallback className=\"rounded-full\">E</AvatarFallback>\n                  </Avatar>\n                  <div className=\"min-w-0 flex-1 text-left\">\n                    <div className=\"truncate font-medium text-sm\">ephraim</div>\n                    <div className=\"truncate text-muted-foreground text-xs\">\n                      ephraim@blocks.so\n                    </div>\n                  </div>\n                </div>\n                <IconLogout className=\"h-4 w-4 shrink-0\" />\n              </SidebarMenuButton>\n            </SidebarMenuItem>\n          </SidebarMenu>\n        </SidebarFooter>\n      </Sidebar>\n\n      {activeItem && activeItemData?.subItems && (\n        <Sidebar\n          className=\"slide-in-from-left-5 w-72 animate-in border-r duration-200\"\n          collapsible=\"none\"\n          side=\"left\"\n          variant=\"sidebar\"\n        >\n          <SidebarHeader className=\"flex flex-row items-center justify-between border-b px-4\">\n            <h3 className=\"font-medium\">{activeItemData.label}</h3>\n            <button\n              className=\"flex h-6 w-6 items-center justify-center rounded-md p-0 hover:bg-sidebar-accent\"\n              onClick={() => setActiveItem(null)}\n            >\n              <IconX className=\"h-4 w-4\" />\n            </button>\n          </SidebarHeader>\n\n          <SidebarContent>\n            <SidebarGroup>\n              <SidebarGroupContent>\n                <SidebarMenu>\n                  {activeItemData.subItems.map((subItem) => {\n                    const SubIcon = subItem.icon;\n                    const isSelected = selectedSubItem === subItem.id;\n\n                    return (\n                      <SidebarMenuItem key={subItem.id}>\n                        <SidebarMenuButton\n                          className=\"h-auto w-full justify-start gap-3 px-3 py-2\"\n                          isActive={isSelected}\n                          onClick={() => handleSubItemClick(subItem)}\n                        >\n                          <SubIcon className=\"mt-0.5 h-5 w-5 shrink-0 self-start\" />\n\n                          <div className=\"min-w-0 flex-1 text-left\">\n                            <div className=\"font-medium\">{subItem.label}</div>\n                            {subItem.description && (\n                              <div className=\"mt-0.5 text-muted-foreground text-xs\">\n                                {subItem.description}\n                              </div>\n                            )}\n                          </div>\n                        </SidebarMenuButton>\n                      </SidebarMenuItem>\n                    );\n                  })}\n                </SidebarMenu>\n              </SidebarGroupContent>\n            </SidebarGroup>\n          </SidebarContent>\n        </Sidebar>\n      )}\n    </div>\n  );\n}\n"
    },
    {
      "path": "content/components/sidebar/sidebar-05/app/page.tsx",
      "type": "registry:page",
      "target": "app/page.tsx",
      "content": "'use client';\n\nimport { SidebarProvider } from '@/components/ui/sidebar';\nimport { AppSidebar } from '@/components/sidebar-05/app-sidebar';\n\nexport default function Page() {\n  return (\n    <SidebarProvider>\n      <div className=\"flex h-dvh w-full\">\n        <AppSidebar />\n      </div>\n    </SidebarProvider>\n  );\n}\n"
    },
    {
      "path": "content/components/sidebar/sidebar-05/team-switcher.tsx",
      "type": "registry:component",
      "target": "components/sidebar-05/team-switcher.tsx",
      "content": "'use client';\n\nimport { ChevronsUpDown, Plus } from 'lucide-react';\nimport * as React from 'react';\n\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuShortcut,\n  DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu';\nimport {\n  SidebarMenu,\n  SidebarMenuButton,\n  SidebarMenuItem,\n  useSidebar,\n} from '@/components/ui/sidebar';\n\nexport function TeamSwitcher({\n  teams,\n}: {\n  teams: {\n    name: string;\n    logo: React.ElementType;\n    plan: string;\n  }[];\n}) {\n  const { isMobile } = useSidebar();\n  const [activeTeam, setActiveTeam] = React.useState(teams[0]);\n\n  if (!activeTeam) {\n    return null;\n  }\n\n  return (\n    <SidebarMenu>\n      <SidebarMenuItem>\n        <DropdownMenu>\n          <DropdownMenuTrigger\n            render={\n              <SidebarMenuButton\n                className=\"data-popup-open:bg-sidebar-accent data-popup-open:text-sidebar-accent-foreground\"\n                size=\"lg\"\n              />\n            }\n          >\n            <div className=\"flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-accent text-sidebar-accent-foreground\">\n              <activeTeam.logo className=\"size-4\" />\n            </div>\n            <div className=\"grid flex-1 text-left text-sm leading-tight\">\n              <span className=\"truncate font-medium\">{activeTeam.name}</span>\n              <span className=\"truncate text-xs\">{activeTeam.plan}</span>\n            </div>\n            <ChevronsUpDown className=\"ml-auto\" />\n          </DropdownMenuTrigger>\n          <DropdownMenuContent\n            align=\"start\"\n            className=\"w-(--anchor-width) min-w-56 rounded-lg\"\n            side={isMobile ? 'bottom' : 'right'}\n            sideOffset={4}\n          >\n            <DropdownMenuLabel className=\"text-muted-foreground text-xs\">\n              Teams\n            </DropdownMenuLabel>\n            {teams.map((team, index) => (\n              <DropdownMenuItem\n                className=\"gap-2 p-2\"\n                key={team.name}\n                onClick={() => setActiveTeam(team)}\n              >\n                <div className=\"flex size-6 items-center justify-center rounded-md border\">\n                  <team.logo className=\"size-3.5 shrink-0\" />\n                </div>\n                {team.name}\n                <DropdownMenuShortcut>⌘{index + 1}</DropdownMenuShortcut>\n              </DropdownMenuItem>\n            ))}\n            <DropdownMenuSeparator />\n            <DropdownMenuItem className=\"gap-2 p-2\">\n              <div className=\"flex size-6 items-center justify-center rounded-md border bg-transparent\">\n                <Plus className=\"size-4\" />\n              </div>\n              <div className=\"font-medium text-muted-foreground\">Add team</div>\n            </DropdownMenuItem>\n          </DropdownMenuContent>\n        </DropdownMenu>\n      </SidebarMenuItem>\n    </SidebarMenu>\n  );\n}\n"
    }
  ],
  "categories": [
    "sidebar"
  ]
}