{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sidebar",
  "title": "Sidebar",
  "author": "AlgorizeTech",
  "description": "A collapsible application sidebar with grouped items, brand header, footer and a mobile drawer. Use it as the primary shell for a dashboard.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "https://avaraui.com/r/tooltip.json",
    "utils"
  ],
  "files": [
    {
      "path": "src/components/custom/blocks/SidebarBlock.tsx",
      "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Menu, X } from \"lucide-react\";\nimport React, { useEffect, useState } from \"react\";\nimport { SidebarContext, useSidebar } from \"./sidebar-context\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"./TooltipBlock\";\n\n// ==========================================\n// 1. PROVIDER & ROOT LAYOUT\n// ==========================================\nexport interface SidebarProviderProps {\n  children: React.ReactNode;\n  defaultExpanded?: boolean;\n  color?: string;\n  className?: string;\n}\n\nexport function SidebarProvider({\n  children,\n  defaultExpanded = true,\n  color = \"primary\",\n  className,\n}: SidebarProviderProps) {\n  const [expanded, setExpanded] = useState(defaultExpanded);\n  const [isMobileOpen, setIsMobileOpen] = useState(false);\n\n  useEffect(() => {\n    const handleResize = () => {\n      if (window.innerWidth >= 768) setIsMobileOpen(false);\n    };\n    window.addEventListener(\"resize\", handleResize);\n    return () => window.removeEventListener(\"resize\", handleResize);\n  }, []);\n\n  return (\n    <SidebarContext.Provider\n      value={{ expanded, setExpanded, isMobileOpen, setIsMobileOpen, color }}\n    >\n      <div\n        className={cn(\n          \"relative flex h-full min-h-screen w-full overflow-hidden bg-muted\",\n          className,\n        )}\n      >\n        {children}\n      </div>\n    </SidebarContext.Provider>\n  );\n}\n\n// ==========================================\n// 2. MAIN SIDEBAR CONTAINER\n// ==========================================\nexport interface SidebarProps extends React.HTMLAttributes<HTMLElement> {\n  variant?: \"attached\" | \"floating\";\n}\n\nexport function Sidebar({\n  variant = \"attached\",\n  className,\n  children,\n  ...props\n}: SidebarProps) {\n  const { expanded, isMobileOpen, setIsMobileOpen } = useSidebar();\n\n  return (\n    <>\n      {/* Backdrop stays mounted so it can fade both in and out with the drawer */}\n      <div\n        aria-hidden={!isMobileOpen}\n        onClick={() => setIsMobileOpen(false)}\n        className={cn(\n          \"fixed inset-0 z-40 bg-black/50 backdrop-blur-sm md:hidden\",\n          \"transition-[opacity,visibility] duration-500 ease-[cubic-bezier(0.32,0.72,0,1)] motion-reduce:transition-none\",\n          isMobileOpen ? \"visible opacity-100\" : \"invisible opacity-0\",\n        )}\n      />\n\n      <aside\n        className={cn(\n          \"fixed inset-y-0 left-0 z-50 flex flex-col md:relative md:translate-x-0\",\n          // Mobile drawer glides in on a decelerating curve; desktop rail keeps the shorter width tween\n          \"transition-[width,transform] duration-500 ease-[cubic-bezier(0.32,0.72,0,1)] will-change-transform motion-reduce:transition-none md:duration-300 md:ease-in-out\",\n          expanded ? \"w-64\" : \"w-16\",\n          isMobileOpen ? \"translate-x-0\" : \"-translate-x-full\",\n          variant === \"attached\"\n            ? \"border-r border-border bg-card text-card-foreground\"\n            : \"m-4 h-[calc(100vh-2rem)] rounded-2xl border border-border bg-card text-card-foreground shadow-sm\",\n          // Lifted off the backdrop while it is an open drawer (mobile only state)\n          isMobileOpen && \"shadow-2xl\",\n          className,\n        )}\n        {...props}\n      >\n        {children}\n      </aside>\n    </>\n  );\n}\n\n// ==========================================\n// 3. HEADER, FOOTER, BRAND\n// ==========================================\nexport function SidebarHeader({\n  className,\n  children,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n  const { expanded, setIsMobileOpen } = useSidebar();\n\n  return (\n    <div\n      className={cn(\n        \"flex h-16 shrink-0 items-center justify-between transition-all\",\n        expanded ? \"px-4\" : \"justify-center px-0\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n      <button\n        onClick={() => setIsMobileOpen(false)}\n        className=\"md:hidden p-1 text-muted-foreground hover:bg-muted rounded-md\"\n      >\n        <X className=\"w-5 h-5\" />\n      </button>\n    </div>\n  );\n}\n\nexport function SidebarBrand({\n  icon,\n  className,\n  children,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement> & { icon?: React.ReactNode }) {\n  const { expanded } = useSidebar();\n\n  return (\n    <div\n      className={cn(\n        \"flex items-center font-bold text-xl text-foreground\",\n        className,\n      )}\n      {...props}\n    >\n      {icon && <div className=\"shrink-0\">{icon}</div>}\n      <div\n        className={cn(\n          \"whitespace-nowrap overflow-hidden transition-all duration-300\",\n          expanded\n            ? \"max-w-[200px] opacity-100 ml-2\"\n            : \"max-w-0 opacity-0 ml-0\",\n        )}\n      >\n        {children}\n      </div>\n    </div>\n  );\n}\n\nexport function SidebarFooter({\n  className,\n  children,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n  return (\n    <div\n      className={cn(\n        \"mt-auto flex shrink-0 flex-col border-t border-border p-3\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </div>\n  );\n}\n\nexport function SidebarContent({\n  className,\n  children,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n  return (\n    <div\n      className={cn(\n        \"flex-1 overflow-y-auto overflow-x-hidden p-3 space-y-4 [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </div>\n  );\n}\n\n// ==========================================\n// 4. GROUPS & ITEMS\n// ==========================================\nexport function SidebarGroup({\n  label,\n  className,\n  children,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement> & { label?: string }) {\n  const { expanded } = useSidebar();\n\n  return (\n    <div className={cn(\"flex flex-col gap-1\", className)} {...props}>\n      {label && (\n        <div\n          className={cn(\n            \"px-3 text-xs font-semibold uppercase tracking-wider text-muted-foreground transition-all duration-300 overflow-hidden\",\n            expanded\n              ? \"max-h-[20px] opacity-100 mb-1\"\n              : \"max-h-0 opacity-0 mb-0\",\n          )}\n        >\n          {label}\n        </div>\n      )}\n      {children}\n    </div>\n  );\n}\n\nexport interface SidebarItemProps\n  extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n  icon?: React.ReactNode;\n  active?: boolean;\n}\n\nexport function SidebarItem({\n  icon,\n  active,\n  className,\n  children,\n  ...props\n}: SidebarItemProps) {\n  const { expanded, color } = useSidebar();\n\n  const item = (\n    <button\n      className={cn(\n        \"group relative flex w-full items-center rounded-lg px-3 py-2 text-sm font-medium transition-all duration-200 outline-none\",\n        !expanded && \"justify-center px-0\",\n        active\n          ? color === \"primary\" || color === \"default\" || !color\n            ? \"bg-primary/10 text-primary font-medium\"\n            : `bg-${color}-50 text-${color}-600 dark:bg-${color}-500/10 dark:text-${color}-400`\n          : \"text-muted-foreground hover:bg-muted hover:text-foreground\",\n        className,\n      )}\n      {...props}\n    >\n      {/* Icon Slot */}\n      {icon && (\n        <div\n          className={cn(\n            \"shrink-0 transition-transform duration-200\",\n            active && \"scale-110\",\n          )}\n        >\n          {icon}\n        </div>\n      )}\n\n      {/* Label Slot (Uses max-w to force strict collapsing) */}\n      <div\n        className={cn(\n          \"whitespace-nowrap overflow-hidden transition-all duration-300 text-left\",\n          expanded\n            ? \"max-w-[200px] opacity-100 ml-3\"\n            : \"max-w-0 opacity-0 ml-0\",\n        )}\n      >\n        {children}\n      </div>\n    </button>\n  );\n\n  // Collapsed rail: the label moves into a Tooltip. It portals to the body,\n  // so it is never clipped by the rail's overflow the way an absolutely\n  // positioned label would be.\n  if (expanded) return item;\n  return (\n    <Tooltip delayDuration={100}>\n      {/* The button is the tab stop; the trigger wrapper only listens. */}\n      <TooltipTrigger className=\"block w-full\" tabIndex={-1}>\n        {item}\n      </TooltipTrigger>\n      <TooltipContent side=\"right\" sideOffset={12} className=\"font-semibold\">\n        {children}\n      </TooltipContent>\n    </Tooltip>\n  );\n}\n\n// ==========================================\n// 5. UTILITY TRIGGERS\n// ==========================================\nexport function SidebarTrigger({\n  className,\n  ...props\n}: React.ButtonHTMLAttributes<HTMLButtonElement>) {\n  const { expanded, setExpanded } = useSidebar();\n\n  return (\n    <button\n      onClick={() => setExpanded(!expanded)}\n      className={cn(\n        \"hidden md:flex p-2 rounded-lg text-muted-foreground hover:bg-muted transition-colors\",\n        className,\n      )}\n      {...props}\n    >\n      <Menu className=\"w-5 h-5\" />\n    </button>\n  );\n}\n\nexport function MobileSidebarTrigger({\n  className,\n  ...props\n}: React.ButtonHTMLAttributes<HTMLButtonElement>) {\n  const { setIsMobileOpen } = useSidebar();\n\n  return (\n    <button\n      onClick={() => setIsMobileOpen(true)}\n      className={cn(\n        \"md:hidden p-2 rounded-lg text-muted-foreground hover:bg-muted transition-colors\",\n        className,\n      )}\n      {...props}\n    >\n      <Menu className=\"w-5 h-5\" />\n    </button>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/custom/blocks/SidebarBlock.tsx"
    },
    {
      "path": "src/components/custom/blocks/sidebar-context.ts",
      "content": "\"use client\";\n\nimport React, { createContext, useContext } from \"react\";\n\ninterface SidebarContextType {\n  expanded: boolean;\n  setExpanded: React.Dispatch<React.SetStateAction<boolean>>;\n  isMobileOpen: boolean;\n  setIsMobileOpen: React.Dispatch<React.SetStateAction<boolean>>;\n  color: string;\n}\n\nexport const SidebarContext = createContext<SidebarContextType | undefined>(undefined);\n\nexport function useSidebar() {\n  const context = useContext(SidebarContext);\n  if (!context)\n    throw new Error(\n      \"Sidebar components must be rendered within a SidebarProvider\",\n    );\n  return context;\n}\n",
      "type": "registry:component",
      "target": "components/custom/blocks/sidebar-context.ts"
    }
  ],
  "docs": "Named exports: SidebarProvider, Sidebar, SidebarHeader, SidebarBrand, SidebarContent, SidebarGroup, SidebarFooter, useSidebar (from sidebar-context.ts, which installs alongside). Wrap your app in SidebarProvider; read `expanded` and `isMobileOpen` from useSidebar to drive your own toggle. Variants: attached | floating. Collapsed item labels show in the `tooltip` item, which installs alongside.",
  "categories": [
    "navigation",
    "layout"
  ],
  "type": "registry:component"
}
