{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sidebar",
  "title": "Sidebar",
  "description": "Sidebar from the Get IT Done design system.",
  "dependencies": [
    "@radix-ui/react-collapsible@^1.2.1",
    "@radix-ui/react-slot@^1.5.0",
    "lucide-react@^0.379.0"
  ],
  "registryDependencies": [
    "https://zero-design.itdone.de/r/dropdown-menu.json",
    "https://zero-design.itdone.de/r/labels-context.json",
    "https://zero-design.itdone.de/r/utils.json",
    "https://zero-design.itdone.de/r/theme.json"
  ],
  "files": [
    {
      "path": "registry/ui/sidebar.tsx",
      "content": "'use client';\n\nimport * as CollapsiblePrimitive from '@radix-ui/react-collapsible';\nimport { Slot } from '@radix-ui/react-slot';\nimport { Check, ChevronDown, Command, Lock, PanelLeft, Plus, Search } from 'lucide-react';\nimport * as React from 'react';\n\nimport { cn } from '@/lib/utils';\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu';\nimport { useLabels, usePreset } from '@/components/ui/labels-context';\n\n// Inset-style app sidebar (Attio pattern, workload.zero `zero` theme): the sidebar sits on the\n// canvas color, the page content is a rounded panel (`SidebarInset`) with a 1px border.\n//\n// Colors come exclusively from the `sidebar-*` and `product-*` token families shipped in\n// the design tokens (`styles/theme.css`, zero theme and every other theme):\n//   bg-sidebar-background, text-sidebar-foreground, bg-sidebar-accent,\n//   text-sidebar-accent-foreground, border-sidebar-border, ring-sidebar-ring,\n//   bg-product-<name>-default, text-product-<name>-on.\n// Never hardcode hex/palette values here. Sizes follow the V9 reference design\n// (workload.zero dashboard prototype, variant v9); house rule: no `.5`\n// Tailwind steps, use arbitrary px values instead.\n\n/* -------------------------------------------------------------------------------------------------\n * Context\n * -----------------------------------------------------------------------------------------------*/\n\n// `hide` removes the sidebar when collapsed (default). `rail` keeps a 56px icon-only rail.\ntype SidebarCollapsedMode = 'hide' | 'rail';\n\ntype SidebarContextValue = {\n  collapsed: boolean;\n  setCollapsed: (collapsed: boolean) => void;\n  toggle: () => void;\n  sidebarId: string;\n  collapsedMode: SidebarCollapsedMode;\n};\n\nconst SidebarContext = React.createContext<SidebarContextValue | null>(null);\n\nfunction useSidebar() {\n  const context = React.useContext(SidebarContext);\n  if (!context) throw new Error('useSidebar must be used within <SidebarLayout> or <SidebarProvider>.');\n  return context;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Layout\n * -----------------------------------------------------------------------------------------------*/\n\ninterface SidebarProviderProps {\n  /** Controlled collapsed state. */\n  collapsed?: boolean;\n  /** Initial collapsed state when uncontrolled. */\n  defaultCollapsed?: boolean;\n  onCollapsedChange?: (collapsed: boolean) => void;\n  /** What collapsing does: `hide` (default) removes the sidebar, `rail` keeps an icon-only 56px rail. */\n  collapsedMode?: SidebarCollapsedMode;\n  children?: React.ReactNode;\n}\n\n// Collapse state for Sidebar, SidebarTrigger and useSidebar without any wrapper element. Use it when the app owns the page layout\n// (SidebarLayout adds a min-h-screen flex wrapper around the same provider).\nfunction SidebarProvider({ collapsed: collapsedProp, defaultCollapsed = false, onCollapsedChange, collapsedMode = 'hide', children }: SidebarProviderProps) {\n  const [uncontrolled, setUncontrolled] = React.useState(defaultCollapsed);\n  const collapsed = collapsedProp ?? uncontrolled;\n  const sidebarId = React.useId();\n\n  const setCollapsed = React.useCallback(\n    (next: boolean) => {\n      if (collapsedProp === undefined) setUncontrolled(next);\n      onCollapsedChange?.(next);\n    },\n    [collapsedProp, onCollapsedChange],\n  );\n\n  const value = React.useMemo(\n    () => ({ collapsed, setCollapsed, toggle: () => setCollapsed(!collapsed), sidebarId, collapsedMode }),\n    [collapsed, setCollapsed, sidebarId, collapsedMode],\n  );\n\n  return <SidebarContext.Provider value={value}>{children}</SidebarContext.Provider>;\n}\n\nconst SidebarLayoutFrame = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ className, ...props }, ref) => {\n  const { collapsed } = useSidebar();\n  return (\n    <div\n      ref={ref}\n      data-state={collapsed ? 'collapsed' : 'expanded'}\n      className={cn('flex min-h-screen w-full bg-sidebar-background text-sidebar-foreground', className)}\n      {...props}\n    />\n  );\n});\nSidebarLayoutFrame.displayName = 'SidebarLayoutFrame';\n\ninterface SidebarLayoutProps extends React.HTMLAttributes<HTMLDivElement>, Omit<SidebarProviderProps, 'children'> {}\n\nconst SidebarLayout = React.forwardRef<HTMLDivElement, SidebarLayoutProps>(\n  ({ className, collapsed, defaultCollapsed, onCollapsedChange, collapsedMode, children, ...props }, ref) => (\n    <SidebarProvider collapsed={collapsed} defaultCollapsed={defaultCollapsed} onCollapsedChange={onCollapsedChange} collapsedMode={collapsedMode}>\n      <SidebarLayoutFrame ref={ref} className={className} {...props}>\n        {children}\n      </SidebarLayoutFrame>\n    </SidebarProvider>\n  ),\n);\nSidebarLayout.displayName = 'SidebarLayout';\n\n// `sticky` (default) pins to the viewport at full height inside SidebarLayout. `fixed` docks to the left edge below the TopBar\n// (top-topbar to the bottom). `static` leaves position and height to the parent.\ntype SidebarPosition = 'sticky' | 'fixed' | 'static';\n\nconst sidebarPositionClasses: Record<SidebarPosition, string> = {\n  sticky: 'sticky top-0 h-screen',\n  fixed: 'fixed bottom-0 left-0 top-topbar z-chrome',\n  static: 'relative',\n};\n\ninterface SidebarProps extends React.HTMLAttributes<HTMLElement> {\n  /** How the sidebar is positioned. Default `sticky` is unchanged. */\n  position?: SidebarPosition;\n}\n\nconst Sidebar = React.forwardRef<HTMLElement, SidebarProps>(\n  ({ className, position = 'sticky', 'aria-label': ariaLabelProp, ...props }, ref) => {\n    const l = useLabels();\n    const ariaLabel = ariaLabelProp ?? l.sidebarMainMenu;\n    // Works inside SidebarLayout (collapse state) and standalone (always expanded).\n    const fallbackId = React.useId();\n    const context = React.useContext(SidebarContext);\n    const collapsed = context?.collapsed ?? false;\n    const sidebarId = context?.sidebarId ?? fallbackId;\n    const collapsedMode = context?.collapsedMode ?? 'hide';\n    const rail = collapsed && collapsedMode === 'rail';\n    const zero = usePreset() === 'zero';\n    return (\n      <nav\n        ref={ref}\n        id={sidebarId}\n        aria-label={ariaLabel}\n        data-state={collapsed ? 'collapsed' : 'expanded'}\n        data-rail={rail || undefined}\n        hidden={collapsed && !rail}\n        className={cn(\n          'group/sb flex w-[248px] shrink-0 flex-col gap-micro overflow-y-auto overflow-x-hidden',\n          zero ? 'p-2 pb-3' : 'py-[10px] pl-[10px] pr-[8px]',\n          'data-[rail]:w-sidebar-collapsed data-[rail]:overflow-x-hidden data-[rail]:px-[10px]',\n          sidebarPositionClasses[position],\n          className,\n        )}\n        {...props}\n      />\n    );\n  },\n);\nSidebar.displayName = 'Sidebar';\n\nconst SidebarHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n  ({ className, ...props }, ref) => <div ref={ref} className={cn('flex flex-col', className)} {...props} />,\n);\nSidebarHeader.displayName = 'SidebarHeader';\n\nconst SidebarContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n  ({ className, ...props }, ref) => (\n    <div ref={ref} className={cn('flex flex-1 flex-col gap-micro', className)} {...props} />\n  ),\n);\nSidebarContent.displayName = 'SidebarContent';\n\nconst SidebarFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n  ({ className, ...props }, ref) => (\n    <div ref={ref} className={cn('mt-auto flex flex-col gap-micro pt-3', className)} {...props} />\n  ),\n);\nSidebarFooter.displayName = 'SidebarFooter';\n\n/** The rounded content panel next to the sidebar. */\nconst SidebarInset = React.forwardRef<HTMLElement, React.HTMLAttributes<HTMLElement>>(\n  ({ className, ...props }, ref) => {\n    const { collapsed, collapsedMode } = useSidebar();\n    return (\n      <main\n        ref={ref}\n        className={cn(\n          'my-2 mr-2 flex min-w-0 flex-1 flex-col rounded-[12px] border border-solid border-sidebar-border bg-background text-text-default shadow-sm',\n          collapsed && collapsedMode === 'hide' && 'ml-2',\n          className,\n        )}\n        {...props}\n      />\n    );\n  },\n);\nSidebarInset.displayName = 'SidebarInset';\n\n/* -------------------------------------------------------------------------------------------------\n * Shared focus style\n * -----------------------------------------------------------------------------------------------*/\n\nconst focusRing =\n  'outline-none focus-visible:ring-2 focus-visible:ring-sidebar-ring focus-visible:ring-offset-2 focus-visible:ring-offset-sidebar-background';\n\n/* -------------------------------------------------------------------------------------------------\n * Trigger\n * -----------------------------------------------------------------------------------------------*/\n\nconst SidebarTrigger = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(\n  ({ className, onClick, children, ...props }, ref) => {\n    const l = useLabels();\n    const { collapsed, toggle, sidebarId } = useSidebar();\n    return (\n      <button\n        ref={ref}\n        type=\"button\"\n        aria-label={collapsed ? l.sidebarExpand : l.sidebarCollapse}\n        aria-expanded={!collapsed}\n        aria-controls={sidebarId}\n        onClick={(event) => {\n          onClick?.(event);\n          if (!event.defaultPrevented) toggle();\n        }}\n        className={cn(\n          'inline-flex h-[24px] w-[24px] shrink-0 items-center justify-center rounded-[6px] text-sidebar-muted-foreground transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',\n          focusRing,\n          className,\n        )}\n        {...props}\n      >\n        {children ?? <PanelLeft className=\"h-4 w-4\" aria-hidden />}\n      </button>\n    );\n  },\n);\nSidebarTrigger.displayName = 'SidebarTrigger';\n\n/* -------------------------------------------------------------------------------------------------\n * Workspace switcher\n * -----------------------------------------------------------------------------------------------*/\n\ninterface SidebarWorkspaceSwitcherProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n  /** Short logo text (e.g. \"GD\") or an element (image). */\n  logo: React.ReactNode;\n  name: string;\n  /** Show the collapse trigger next to the switcher. Default true. */\n  showTrigger?: boolean;\n  /** Opt-in: renders the trigger as a menu button listing these workspaces. Without it the trigger is a plain button. */\n  workspaces?: SidebarWorkspace[];\n  activeWorkspaceId?: string;\n  onWorkspaceChange?: (id: string) => void;\n  /** Personal entry below the workspace list. */\n  personal?: { name: string; avatar?: React.ReactNode; onSelect?: () => void };\n  /** Adds the Create workspace entry. */\n  onCreateWorkspace?: () => void;\n  workspacesLabel?: string;\n  createLabel?: string;\n}\n\ninterface SidebarWorkspace {\n  id: string;\n  name: string;\n  logo?: React.ReactNode;\n}\n\nconst SidebarWorkspaceSwitcher = React.forwardRef<HTMLButtonElement, SidebarWorkspaceSwitcherProps>(\n  (\n    {\n      className,\n      logo,\n      name,\n      showTrigger = true,\n      workspaces,\n      activeWorkspaceId,\n      onWorkspaceChange,\n      personal,\n      onCreateWorkspace,\n      workspacesLabel: workspacesLabelProp,\n      createLabel: createLabelProp,\n      ...props\n    },\n    ref,\n  ) => {\n    const l = useLabels();\n    const workspacesLabel = workspacesLabelProp ?? l.workspaces;\n    const createLabel = createLabelProp ?? l.createWorkspace;\n    const trigger = (\n      <button\n        ref={ref}\n        type=\"button\"\n        className={cn(\n          'flex min-w-0 flex-1 items-center gap-2 rounded-[8px] p-[6px] text-left transition-colors hover:bg-sidebar-accent',\n          focusRing,\n          className,\n        )}\n        {...props}\n      >\n        <span\n          aria-hidden\n          className=\"grid h-[24px] w-[24px] shrink-0 place-items-center overflow-hidden rounded-logo-tile-24 bg-sidebar-accent-foreground text-logo-tile-24 font-bold text-sidebar-background\"\n        >\n          {logo}\n        </span>\n        <span className=\"typography-ui-lg-semibold truncate text-sidebar-accent-foreground group-data-[rail]/sb:sr-only\">\n          {name}\n        </span>\n        <ChevronDown\n          className=\"h-[14px] w-[14px] shrink-0 text-sidebar-muted-foreground group-data-[rail]/sb:hidden\"\n          aria-hidden\n        />\n      </button>\n    );\n    return (\n      <div className=\"flex items-center gap-1 group-data-[rail]/sb:flex-col\">\n        {workspaces ? (\n          <DropdownMenu>\n            <DropdownMenuTrigger asChild>{trigger}</DropdownMenuTrigger>\n            <DropdownMenuContent align=\"start\" className=\"w-60\">\n              <DropdownMenuLabel>{workspacesLabel}</DropdownMenuLabel>\n              {workspaces.map((workspace) => (\n                <DropdownMenuItem\n                  key={workspace.id}\n                  aria-current={workspace.id === activeWorkspaceId ? 'true' : undefined}\n                  onSelect={() => onWorkspaceChange?.(workspace.id)}\n                  className={cn(workspace.id === activeWorkspaceId && 'bg-muted')}\n                >\n                  {workspace.logo && (\n                    <span aria-hidden className=\"grid h-5 w-5 shrink-0 place-items-center overflow-hidden rounded-logo-tile-20 bg-background-brand-bold-default text-logo-tile-20 font-bold leading-none text-text-on-brand\">\n                      {workspace.logo}\n                    </span>\n                  )}\n                  <span className=\"min-w-0 flex-1 truncate\">{workspace.name}</span>\n                  {workspace.id === activeWorkspaceId && <Check className=\"h-icon-sm w-icon-sm shrink-0\" aria-hidden />}\n                </DropdownMenuItem>\n              ))}\n              {personal && (\n                <>\n                  <DropdownMenuSeparator />\n                  <DropdownMenuItem onSelect={() => personal.onSelect?.()}>\n                    {personal.avatar}\n                    <span className=\"min-w-0 flex-1 truncate\">{personal.name}</span>\n                  </DropdownMenuItem>\n                </>\n              )}\n              {onCreateWorkspace && (\n                <>\n                  <DropdownMenuSeparator />\n                  <DropdownMenuItem onSelect={onCreateWorkspace}>\n                    <Plus className=\"h-icon-sm w-icon-sm shrink-0\" aria-hidden />\n                    {createLabel}\n                  </DropdownMenuItem>\n                </>\n              )}\n            </DropdownMenuContent>\n          </DropdownMenu>\n        ) : (\n          trigger\n        )}\n        {showTrigger && <SidebarTrigger />}\n      </div>\n    );\n  },\n);\nSidebarWorkspaceSwitcher.displayName = 'SidebarWorkspaceSwitcher';\n\n/* -------------------------------------------------------------------------------------------------\n * Quick actions + search\n * -----------------------------------------------------------------------------------------------*/\n\nconst SidebarKbd = ({ className, ...props }: React.HTMLAttributes<HTMLElement>) => (\n  <kbd\n    className={cn(\n      'ml-auto rounded-[4px] border border-solid border-sidebar-border bg-sidebar-background px-1 font-sans text-micro leading-[16px] text-sidebar-muted-foreground',\n      className,\n    )}\n    {...props}\n  />\n);\n\ninterface SidebarQuickActionsProps extends React.HTMLAttributes<HTMLDivElement> {\n  label?: string;\n  shortcut?: string;\n  searchLabel?: string;\n  searchShortcut?: string;\n  onQuickActions?: () => void;\n  onSearch?: () => void;\n}\n\nconst quickButton =\n  'flex h-[30px] items-center gap-2 rounded-[8px] border border-solid border-sidebar-border bg-background px-2 text-ui text-sidebar-accent-foreground shadow-sm transition-colors hover:bg-sidebar-accent';\n\nconst SidebarQuickActions = React.forwardRef<HTMLDivElement, SidebarQuickActionsProps>(\n  (\n    {\n      className,\n      label: labelProp,\n      shortcut = '⌘K',\n      searchLabel: searchLabelProp,\n      searchShortcut = '/',\n      onQuickActions,\n      onSearch,\n      ...props\n    },\n    ref,\n  ) => {\n    const l = useLabels();\n    const label = labelProp ?? l.quickActions;\n    const searchLabel = searchLabelProp ?? l.sidebarSearch;\n    const zero = usePreset() === 'zero';\n    return (\n    <div\n      ref={ref}\n      className={cn('my-2 grid grid-cols-[1fr_auto] group-data-[rail]/sb:grid-cols-1', zero ? 'gap-2' : 'gap-[6px]', className)}\n      {...props}\n    >\n      <button type=\"button\" onClick={onQuickActions} className={cn(quickButton, focusRing)} aria-keyshortcuts=\"Meta+K\">\n        <Command className=\"h-4 w-4 shrink-0\" aria-hidden />\n        <span className=\"truncate group-data-[rail]/sb:sr-only\">{label}</span>\n        <SidebarKbd aria-hidden className=\"group-data-[rail]/sb:hidden\">\n          {shortcut}\n        </SidebarKbd>\n      </button>\n      <button\n        type=\"button\"\n        onClick={onSearch}\n        aria-label={searchLabel}\n        aria-keyshortcuts={searchShortcut}\n        className={cn(quickButton, focusRing)}\n      >\n        <Search className=\"h-4 w-4 shrink-0\" aria-hidden />\n        <SidebarKbd aria-hidden className=\"group-data-[rail]/sb:hidden\">\n          {searchShortcut}\n        </SidebarKbd>\n      </button>\n    </div>\n  );\n  },\n);\nSidebarQuickActions.displayName = 'SidebarQuickActions';\n\n/* -------------------------------------------------------------------------------------------------\n * Nav item\n * -----------------------------------------------------------------------------------------------*/\n\ninterface SidebarNavItemProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n  icon?: React.ReactNode;\n  label: React.ReactNode;\n  /** Muted text right after the label (e.g. a long project name). */\n  secondary?: React.ReactNode;\n  /** Number shown on the right, e.g. open items. */\n  count?: number;\n  /** Text shown on the right instead of a count, e.g. \"aktivieren\". */\n  trailing?: React.ReactNode;\n  active?: boolean;\n  /** `location` marks an in-page anchor section instead of the current page. Implies active. */\n  current?: 'page' | 'location';\n  /** Render the child element (e.g. a Next.js Link) instead of an <a>. */\n  asChild?: boolean;\n  /** `nav` uses the nav-item / nav-item-current type roles and nav-item padding and gap tokens; `default` is unchanged. */\n  variant?: 'default' | 'nav';\n  /** Dims the item and removes it from the tab order. Rendered as `aria-disabled`. */\n  disabled?: boolean;\n  /** Small status dot on the right (e.g. unread activity). Pair with a visually hidden label if it carries meaning. */\n  dot?: boolean;\n  /** Integration status dot on the right (6px status-dot size): `on` = connected (success), `off` = not connected (subtle). Announced as text for screen readers. */\n  statusDot?: 'on' | 'off';\n  /** Lock icon on the right for a locked or read-only entry. Announced as text for screen readers. */\n  locked?: boolean;\n}\n\nconst SidebarNavItem = React.forwardRef<HTMLAnchorElement, SidebarNavItemProps>(\n  (\n    {\n      className,\n      icon,\n      label,\n      secondary,\n      count,\n      trailing,\n      active: activeProp = false,\n      current,\n      asChild = false,\n      variant = 'default',\n      disabled = false,\n      dot = false,\n      statusDot,\n      locked = false,\n      children,\n      onClick,\n      ...props\n    },\n    ref,\n  ) => {\n    const l = useLabels();\n    const active = activeProp || current !== undefined;\n    const nav = variant === 'nav';\n    const zero = usePreset() === 'zero';\n    // Only the first right-aligned extra pushes itself to the end.\n    const pushRight = count === undefined && trailing === undefined && !dot;\n    const Comp = asChild ? Slot : 'a';\n    const content = (\n      <>\n        {icon && (\n          <span className=\"flex h-[18px] w-[18px] shrink-0 items-center justify-center [&>svg]:h-4 [&>svg]:w-4\" aria-hidden>\n            {icon}\n          </span>\n        )}\n        <span className={cn('truncate', secondary && 'shrink-0', 'group-data-[rail]/sb:sr-only')}>{label}</span>\n        {secondary && (\n          <span className=\"min-w-0 truncate font-normal text-sidebar-muted-foreground group-data-[rail]/sb:hidden\">\n            {secondary}\n          </span>\n        )}\n        {count !== undefined && (\n          <span\n            className={cn(\n              'ml-auto tabular-nums text-sidebar-muted-foreground group-data-[rail]/sb:hidden',\n              nav ? 'typography-ui-sm' : 'text-[12px] font-normal',\n            )}\n          >\n            {count}\n          </span>\n        )}\n        {trailing !== undefined && count === undefined && (\n          <span className=\"ml-auto text-[12px] font-normal text-sidebar-muted-foreground group-data-[rail]/sb:hidden\">\n            {trailing}\n          </span>\n        )}\n        {dot && (\n          <span\n            aria-hidden\n            className=\"ml-auto h-2 w-2 shrink-0 rounded-full bg-background-brand-bold-default group-data-[rail]/sb:hidden\"\n          />\n        )}\n        {locked && (\n          <span\n            data-locked=\"\"\n            className={cn('flex shrink-0 text-icon-subtle group-data-[rail]/sb:hidden', pushRight && 'ml-auto')}\n          >\n            <Lock aria-hidden className=\"h-icon-2xs w-icon-2xs\" />\n            <span className=\"sr-only\">{l.locked}</span>\n          </span>\n        )}\n        {/* Token gap: size-status-dot (6px) has a CSS variable in 4.17.0 but no Tailwind h-/w- utility in tailwind.theme.cjs, so the variable is referenced directly. */}\n        {statusDot && (\n          <span\n            data-status-dot={statusDot}\n            className={cn('flex shrink-0 group-data-[rail]/sb:hidden', pushRight && !locked && 'ml-auto', locked && 'ml-2')}\n          >\n            <span\n              aria-hidden\n              className={cn(\n                'h-[var(--size-status-dot)] w-[var(--size-status-dot)] rounded-full',\n                statusDot === 'on' ? 'bg-status-success-dot' : 'bg-text-subtlest',\n              )}\n            />\n            <span className=\"sr-only\">{statusDot === 'on' ? l.statusActive : l.statusInactive}</span>\n          </span>\n        )}\n      </>\n    );\n    return (\n      <Comp\n        ref={ref}\n        aria-current={current ?? (active ? 'page' : undefined)}\n        aria-disabled={disabled || undefined}\n        tabIndex={disabled ? -1 : props.tabIndex}\n        onClick={\n          disabled\n            ? (event: React.MouseEvent<HTMLAnchorElement>) => {\n                event.preventDefault();\n              }\n            : onClick\n        }\n        data-active={active || undefined}\n        data-disabled={disabled || undefined}\n        className={cn(\n          'flex h-[30px] items-center text-sidebar-foreground no-underline transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',\n          'data-[active]:bg-sidebar-accent data-[active]:text-sidebar-accent-foreground',\n          'data-[disabled]:pointer-events-none data-[disabled]:text-text-disabled',\n          'group-data-[rail]/sb:justify-center group-data-[rail]/sb:px-0',\n          zero ? 'rounded-item' : 'rounded-[7px]',\n          nav\n            ? 'typography-nav-item gap-[var(--size-nav-item-gap)] px-[var(--size-nav-item-padding-x)] data-[active]:typography-nav-item-current'\n            : 'gap-2 px-2 text-[14px] data-[active]:font-medium',\n          focusRing,\n          className,\n        )}\n        {...props}\n      >\n        {asChild ? children : content}\n      </Comp>\n    );\n  },\n);\nSidebarNavItem.displayName = 'SidebarNavItem';\n\n/* -------------------------------------------------------------------------------------------------\n * Section (collapsible group) + tree\n * -----------------------------------------------------------------------------------------------*/\n\ninterface SidebarSectionProps extends Omit<React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Root>, 'title'> {\n  label: React.ReactNode;\n  /** Optional action rendered next to the label, e.g. an \"add\" icon button. */\n  action?: React.ReactNode;\n}\n\nconst SidebarSection = React.forwardRef<React.ElementRef<typeof CollapsiblePrimitive.Root>, SidebarSectionProps>(\n  ({ className, label, action, defaultOpen = true, children, ...props }, ref) => {\n    const zero = usePreset() === 'zero';\n    return (\n    <CollapsiblePrimitive.Root\n      ref={ref}\n      defaultOpen={defaultOpen}\n      className={cn('group/section flex flex-col gap-micro', zero ? 'mt-3' : 'mt-[14px]', className)}\n      {...props}\n    >\n      <div className={cn('flex items-center group-data-[rail]/sb:hidden', zero ? 'min-h-target px-2' : 'px-[6px]')}>\n        <CollapsiblePrimitive.Trigger\n          className={cn(\n            'typography-ui-sm flex min-h-target items-center gap-1 pr-1 text-sidebar-muted-foreground transition-colors hover:text-sidebar-accent-foreground',\n            zero ? 'rounded-item' : 'rounded-[5px]',\n            focusRing,\n          )}\n        >\n          <ChevronDown\n            className=\"h-[14px] w-[14px] transition-transform group-data-[state=closed]/section:-rotate-90\"\n            aria-hidden\n          />\n          {label}\n        </CollapsiblePrimitive.Trigger>\n        {action && <span className=\"ml-auto flex\">{action}</span>}\n      </div>\n      <CollapsiblePrimitive.Content className=\"flex flex-col gap-micro\">{children}</CollapsiblePrimitive.Content>\n    </CollapsiblePrimitive.Root>\n    );\n  },\n);\nSidebarSection.displayName = 'SidebarSection';\n\n/** Small icon button for a section action (e.g. \"+\"). Needs an aria-label. */\nconst SidebarSectionAction = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(\n  ({ className, ...props }, ref) => (\n    <button\n      ref={ref}\n      type=\"button\"\n      className={cn(\n        'inline-flex h-[24px] w-[24px] items-center justify-center rounded-[6px] text-sidebar-muted-foreground transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground [&>svg]:h-[14px] [&>svg]:w-[14px]',\n        focusRing,\n        className,\n      )}\n      {...props}\n    />\n  ),\n);\nSidebarSectionAction.displayName = 'SidebarSectionAction';\n\ninterface SidebarTreeProps extends React.HTMLAttributes<HTMLDivElement> {\n  /** Nesting level. `1` indents a tree inside another tree by 15px more. Default 0 is unchanged. */\n  level?: 0 | 1;\n}\n\n/** Indented children with a 1px guide line on the left. */\nconst SidebarTree = React.forwardRef<HTMLDivElement, SidebarTreeProps>(\n  ({ className, level = 0, ...props }, ref) => {\n    const zero = usePreset() === 'zero';\n    return (\n    <div\n      ref={ref}\n      role=\"group\"\n      data-level={level || undefined}\n      className={cn(\n        'flex flex-col border-0 border-l border-solid border-sidebar-border pl-2 group-data-[rail]/sb:hidden',\n        zero ? 'ml-4 gap-micro' : 'ml-[15px] gap-px',\n        level === 1 && (zero ? 'ml-8' : 'ml-[30px]'),\n        className,\n      )}\n      {...props}\n    />\n    );\n  },\n);\nSidebarTree.displayName = 'SidebarTree';\n\n/* -------------------------------------------------------------------------------------------------\n * Object icon (product) + swatch (project)\n * -----------------------------------------------------------------------------------------------*/\n\ntype SidebarProduct = 'workstream' | 'backoffice' | 'coldcall' | 'vacancy' | 'jobsearch';\n\n// Full class strings so Tailwind's content scan picks every product token up.\nconst productClasses: Record<SidebarProduct, string> = {\n  workstream: 'bg-product-workstream-default text-product-workstream-on',\n  backoffice: 'bg-product-backoffice-default text-product-backoffice-on',\n  coldcall: 'bg-product-coldcall-default text-product-coldcall-on',\n  vacancy: 'bg-product-vacancy-default text-product-vacancy-on',\n  jobsearch: 'bg-product-jobsearch-default text-product-jobsearch-on',\n};\n\ninterface SidebarObjectIconProps extends React.HTMLAttributes<HTMLSpanElement> {\n  /** Product color. Omit and pass className for other objects (e.g. Contacts). */\n  product?: SidebarProduct;\n  /** Uses the page's product context (`<html data-product=\"…\">`). */\n  contextual?: boolean;\n}\n\nconst SidebarObjectIcon = React.forwardRef<HTMLSpanElement, SidebarObjectIconProps>(\n  ({ className, product, contextual = false, ...props }, ref) => {\n    const zero = usePreset() === 'zero';\n    return (\n    <span\n      ref={ref}\n      aria-hidden\n      className={cn(\n        'grid h-[18px] w-[18px] shrink-0 place-items-center [&>svg]:h-3 [&>svg]:w-3 [&>svg]:stroke-[2.25]',\n        zero ? 'rounded-tight' : 'rounded-[5px]',\n        product && productClasses[product],\n        contextual && 'bg-product-accent-default text-product-accent-on',\n        className,\n      )}\n      {...props}\n    />\n    );\n  },\n);\nSidebarObjectIcon.displayName = 'SidebarObjectIcon';\n\ninterface SidebarSwatchProps extends React.HTMLAttributes<HTMLSpanElement> {\n  /** `sm` is the 8px square with hairline radius used inline in the top bar. Default 10px. */\n  size?: 'default' | 'sm';\n  /**\n   * User-defined project color (data, not design). Passed as a CSS color value at runtime,\n   * e.g. from the project record; the component itself defines no color.\n   */\n  color: string;\n}\n\n/** 10px colored square for user-colored records such as projects. */\nconst SidebarSwatch = ({ className, color, size = 'default', style, ...props }: SidebarSwatchProps) => (\n  <span\n    aria-hidden\n    className={cn(\n      'block shrink-0',\n      size === 'sm' ? 'h-2 w-2 rounded-hairline' : 'mx-1 h-swatch-sm w-swatch-sm rounded-[3px]',\n      className,\n    )}\n    style={{ backgroundColor: color, ...style }}\n    {...props}\n  />\n);\n\nexport {\n  Sidebar,\n  SidebarContent,\n  SidebarFooter,\n  SidebarHeader,\n  SidebarInset,\n  SidebarKbd,\n  SidebarLayout,\n  SidebarProvider,\n  SidebarNavItem,\n  SidebarObjectIcon,\n  SidebarQuickActions,\n  SidebarSection,\n  SidebarSectionAction,\n  SidebarSwatch,\n  SidebarTree,\n  SidebarTrigger,\n  SidebarWorkspaceSwitcher,\n  useSidebar,\n  type SidebarCollapsedMode,\n  type SidebarLayoutProps,\n  type SidebarProviderProps,\n  type SidebarPosition,\n  type SidebarProps,\n  type SidebarTreeProps,\n  type SidebarWorkspace,\n  type SidebarNavItemProps,\n  type SidebarObjectIconProps,\n  type SidebarProduct,\n  type SidebarQuickActionsProps,\n  type SidebarSectionProps,\n  type SidebarSwatchProps,\n  type SidebarWorkspaceSwitcherProps,\n};\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}