{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "components-app-shells-app-shell-1",
  "title": "App Shell 1",
  "description": "Collapsible sidebar app shell with search command palette, breadcrumb page header, scrollable nav sections, and avatar-based user dropdown.",
  "dependencies": [
    "@hugeicons/react",
    "@hugeicons/core-free-icons"
  ],
  "registryDependencies": [
    "sidebar",
    "breadcrumb",
    "dropdown-menu",
    "separator",
    "dialog",
    "avatar",
    "@odysseyui/components-primitives-avatar"
  ],
  "files": [
    {
      "path": "registry/components/app-shells/app-shell-1/index.tsx",
      "content": "'use client';\nimport React, { useState, useCallback, useEffect, useMemo } from 'react';\nimport Link from 'next/link';\nimport { usePathname, useRouter } from 'next/navigation';\nimport {\n  Sidebar,\n  SidebarContent,\n  SidebarFooter,\n  SidebarGroup,\n  SidebarGroupContent,\n  SidebarGroupLabel,\n  SidebarHeader,\n  SidebarMenu,\n  SidebarMenuButton,\n  SidebarMenuItem,\n  SidebarRail,\n  SidebarTrigger,\n  useSidebar,\n} from '@/components/ui/sidebar';\nimport {\n  Breadcrumb,\n  BreadcrumbItem,\n  BreadcrumbLink,\n  BreadcrumbList,\n  BreadcrumbPage,\n  BreadcrumbSeparator,\n} from '@/components/ui/breadcrumb';\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogHeader,\n  DialogTitle,\n} from '@/components/ui/dialog';\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu';\nimport {\n  Avatar as UIAvatar,\n  AvatarFallback,\n  AvatarImage,\n} from '@/components/ui/avatar';\nimport { Separator } from '@/components/ui/separator';\nimport { HugeiconsIcon } from '@hugeicons/react';\nimport {\n  SearchIcon,\n  CommandLineIcon,\n  RobotIcon,\n  BookOpen01Icon,\n  Settings02Icon,\n  FramerIcon,\n  PieChartIcon,\n  MapsIcon,\n  ArrowRight01Icon,\n  Logout01Icon,\n  User02Icon,\n  UnfoldMoreIcon,\n  KeyboardIcon,\n} from '@hugeicons/core-free-icons';\nimport OdysseyAvatar, {\n  type AvatarColor,\n} from '@/components/odyssey/components/primitives/avatar';\nimport { cn } from '@/lib/utils';\nimport Image from 'next/image';\nimport type { AppShell1Config, SidebarSection } from './app-shell-1.config';\nimport { appShell1Config as defaultConfig } from './app-shell-1.config';\n\n// ─── Kbd ──────────────────────────────────────────────────────────────────────\nfunction Kbd({\n  children,\n  className,\n}: {\n  children: React.ReactNode;\n  className?: string;\n}) {\n  return (\n    <kbd\n      className={cn(\n        'inline-flex h-5 min-w-5 items-center justify-center rounded border bg-muted px-1 text-[11px] font-medium text-muted-foreground',\n        className,\n      )}\n    >\n      {children}\n    </kbd>\n  );\n}\n\n// ─── Icon map ─────────────────────────────────────────────────────────────────\nconst iconMap: Record<string, any> = {\n  SquareTerminal: CommandLineIcon,\n  Bot: RobotIcon,\n  BookOpen: BookOpen01Icon,\n  Settings2: Settings02Icon,\n  Frame: FramerIcon,\n  PieChart: PieChartIcon,\n  Map: MapsIcon,\n};\n\n// ─── Avatar color helper ──────────────────────────────────────────────────────\nconst AVATAR_COLORS: AvatarColor[] = [\n  'blue',\n  'orange',\n  'red',\n  'green',\n  'purple',\n  'yellow',\n  'cyan',\n  'pink',\n  'indigo',\n  'lime',\n  'turquoise',\n  'violet',\n];\n\nfunction getAvatarColor(seed: string): AvatarColor {\n  const n = seed.split('').reduce((acc, c) => acc + c.charCodeAt(0), 0);\n  return AVATAR_COLORS[n % AVATAR_COLORS.length];\n}\n\n// ─── Shortcuts Modal ──────────────────────────────────────────────────────────\nconst SHORTCUTS = [\n  { label: 'Open search', keys: ['⌘', 'K'] },\n  { label: 'Toggle sidebar', keys: ['⌘', 'B'] },\n] as const;\n\nfunction ShortcutsModal({\n  open,\n  onOpenChange,\n}: {\n  open: boolean;\n  onOpenChange: (open: boolean) => void;\n}) {\n  return (\n    <Dialog open={open} onOpenChange={onOpenChange}>\n      <DialogHeader className=\"sr-only\">\n        <DialogTitle>Keyboard shortcuts</DialogTitle>\n        <DialogDescription>Available keyboard shortcuts</DialogDescription>\n      </DialogHeader>\n      <DialogContent className=\"sm:max-w-xs\">\n        <div className=\"mb-4 flex flex-col gap-1\">\n          <p className=\"text-sm font-semibold\">Keyboard shortcuts</p>\n          <p className=\"text-xs text-muted-foreground\">\n            Navigate faster with these shortcuts\n          </p>\n        </div>\n        <div className=\"flex flex-col gap-3\">\n          {SHORTCUTS.map((s) => (\n            <div key={s.label} className=\"flex items-center justify-between\">\n              <span className=\"text-sm text-muted-foreground\">{s.label}</span>\n              <span className=\"flex items-center gap-0.5\">\n                {s.keys.map((k) => (\n                  <Kbd key={k}>{k}</Kbd>\n                ))}\n              </span>\n            </div>\n          ))}\n        </div>\n      </DialogContent>\n    </Dialog>\n  );\n}\n\n// ─── Shared user avatar + menu ────────────────────────────────────────────────\nfunction UserAvatar({\n  src,\n  name,\n  color,\n}: {\n  src: string;\n  name: string;\n  color: AvatarColor;\n}) {\n  return (\n    <UIAvatar className=\"size-8\">\n      <AvatarImage src={src} alt={name} />\n      <AvatarFallback className=\"overflow-hidden bg-transparent p-0\">\n        <OdysseyAvatar color={color} size=\"sm\" />\n      </AvatarFallback>\n    </UIAvatar>\n  );\n}\n\nfunction UserMenuContent({\n  src,\n  name,\n  email,\n  color,\n  profileHref,\n  onLogout,\n  onShortcuts,\n}: {\n  src: string;\n  name: string;\n  email: string;\n  color: AvatarColor;\n  profileHref: string;\n  onLogout?: () => void;\n  onShortcuts: () => void;\n}) {\n  return (\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            <UserAvatar src={src} name={name} color={color} />\n            <div className=\"grid flex-1 text-left text-sm leading-tight\">\n              <span className=\"truncate font-medium\">{name}</span>\n              <span className=\"truncate text-xs text-muted-foreground\">\n                {email}\n              </span>\n            </div>\n          </div>\n        </DropdownMenuLabel>\n      </DropdownMenuGroup>\n      <DropdownMenuSeparator />\n      <DropdownMenuGroup>\n        <DropdownMenuItem asChild>\n          <Link href={profileHref}>\n            <HugeiconsIcon icon={User02Icon} strokeWidth={2} />\n            Profile\n          </Link>\n        </DropdownMenuItem>\n        <DropdownMenuItem onClick={onShortcuts}>\n          <HugeiconsIcon icon={KeyboardIcon} strokeWidth={2} />\n          Shortcuts\n        </DropdownMenuItem>\n      </DropdownMenuGroup>\n      <DropdownMenuSeparator />\n      <DropdownMenuItem variant=\"destructive\" onClick={onLogout}>\n        <HugeiconsIcon icon={Logout01Icon} strokeWidth={2} />\n        Log out\n      </DropdownMenuItem>\n    </>\n  );\n}\n\n// ─── Types ────────────────────────────────────────────────────────────────────\nexport interface SidebarUserInfo {\n  name?: string;\n  email?: string;\n  avatar?: string;\n}\n\nexport interface AppShell1SearchProps {\n  config: AppShell1Config;\n  open: boolean;\n  onOpenChange: (open: boolean) => void;\n}\n\nexport interface AppShell1PageHeaderProps {\n  pageName: string;\n  breadcrumbs?: Array<{ label: string; href?: string }>;\n  actions?: React.ReactNode;\n  user?: SidebarUserInfo;\n  profileHref?: string;\n  onLogout?: () => void;\n}\n\nexport interface AppShell1Props {\n  config?: AppShell1Config;\n  collapsibleSubsections?: boolean;\n  user?: SidebarUserInfo;\n  profileHref?: string;\n  onLogout?: () => void;\n}\n\n// ─── Search Modal ─────────────────────────────────────────────────────────────\nexport function AppShell1Search({\n  config,\n  open,\n  onOpenChange,\n}: AppShell1SearchProps) {\n  const router = useRouter();\n  const [query, setQuery] = useState('');\n  const filtered = useMemo(() => {\n    if (!query.trim()) return config.sections;\n    const q = query.toLowerCase();\n    return config.sections\n      .map((section) => ({\n        ...section,\n        items: section.items.filter(\n          (item) =>\n            item.title.toLowerCase().includes(q) ||\n            item.keywords?.some((kw) => kw.toLowerCase().includes(q)) ||\n            section.label.toLowerCase().includes(q),\n        ),\n      }))\n      .filter((section) => section.items.length > 0);\n  }, [config.sections, query]);\n\n  const runCommand = useCallback(\n    (command: () => unknown) => {\n      onOpenChange(false);\n      setQuery('');\n      command();\n    },\n    [onOpenChange],\n  );\n\n  useEffect(() => {\n    const down = (e: KeyboardEvent) => {\n      if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {\n        if (\n          (e.target instanceof HTMLElement && e.target.isContentEditable) ||\n          e.target instanceof HTMLInputElement ||\n          e.target instanceof HTMLTextAreaElement ||\n          e.target instanceof HTMLSelectElement\n        )\n          return;\n        e.preventDefault();\n        onOpenChange(!open);\n      }\n    };\n    document.addEventListener('keydown', down);\n    return () => document.removeEventListener('keydown', down);\n  }, [open, onOpenChange]);\n\n  useEffect(() => {\n    if (!open) setQuery('');\n  }, [open]);\n\n  return (\n    <Dialog onOpenChange={onOpenChange} open={open}>\n      <DialogHeader className=\"sr-only\">\n        <DialogTitle>Search pages</DialogTitle>\n        <DialogDescription>Navigate to a page quickly</DialogDescription>\n      </DialogHeader>\n      <DialogContent\n        className=\"top-1/4 translate-y-0 gap-0 overflow-hidden rounded-xl border-none p-0 shadow-2xl sm:max-w-xl\"\n        showCloseButton={false}\n      >\n        <div className=\"flex items-center border-b px-3\">\n          <HugeiconsIcon\n            icon={SearchIcon}\n            strokeWidth={2}\n            className=\"mr-2 size-4 shrink-0 opacity-50\"\n          />\n          <input\n            value={query}\n            onChange={(e) => setQuery(e.target.value)}\n            placeholder=\"Search pages...\"\n            className=\"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\"\n          />\n        </div>\n        <div className=\"relative max-h-72 overflow-y-auto\">\n          {filtered.length === 0 ? (\n            <p className=\"py-12 text-center text-sm text-muted-foreground\">\n              No results found.\n            </p>\n          ) : (\n            filtered.map((section) => (\n              <div key={section.label} className=\"overflow-hidden p-1\">\n                <div className=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\n                  {section.label}\n                </div>\n                {section.items.map((item) => (\n                  <button\n                    key={item.href}\n                    onClick={() => runCommand(() => router.push(item.href))}\n                    className=\"relative flex w-full cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground\"\n                  >\n                    <HugeiconsIcon\n                      icon={ArrowRight01Icon}\n                      strokeWidth={2}\n                      className=\"size-4\"\n                    />\n                    {item.title}\n                  </button>\n                ))}\n              </div>\n            ))\n          )}\n        </div>\n        <div className=\"flex h-9 items-center justify-between border-t px-4 text-xs text-muted-foreground\">\n          <div className=\"flex gap-4\">\n            <span className=\"flex items-center gap-1.5\">\n              <Kbd>↩</Kbd>\n              <span>Select</span>\n            </span>\n            <span className=\"flex items-center gap-1.5\">\n              <Kbd>↑↓</Kbd>\n              <span>Navigate</span>\n            </span>\n          </div>\n          <span className=\"flex items-center gap-1.5\">\n            <Kbd>Esc</Kbd>\n            <span>Close</span>\n          </span>\n        </div>\n      </DialogContent>\n    </Dialog>\n  );\n}\n\n// ─── Page Header ──────────────────────────────────────────────────────────────\nexport function AppShell1PageHeader({\n  pageName,\n  breadcrumbs,\n  actions,\n  user,\n  profileHref = '/profile',\n  onLogout,\n}: AppShell1PageHeaderProps) {\n  const userName = user?.name || 'User';\n  const userEmail = user?.email || 'user@example.com';\n  const avatarSrc = user?.avatar || '';\n  const avatarColor = getAvatarColor(userName);\n  const [shortcutsOpen, setShortcutsOpen] = useState(false);\n\n  return (\n    <>\n      <header className=\"flex h-14 shrink-0 items-center gap-2 border-b px-4\">\n        <div className=\"flex flex-1 items-center gap-2\">\n          <SidebarTrigger className=\"-ml-1\" />\n          <Separator\n            orientation=\"vertical\"\n            className=\"mr-2 data-vertical:h-4 data-vertical:self-auto\"\n          />\n          <Breadcrumb>\n            <BreadcrumbList>\n              {breadcrumbs && breadcrumbs.length > 0 ? (\n                breadcrumbs.map((crumb, index) => {\n                  const isLast = index === breadcrumbs.length - 1;\n                  return (\n                    <React.Fragment key={index}>\n                      <BreadcrumbItem>\n                        {!isLast && crumb.href ? (\n                          <BreadcrumbLink href={crumb.href}>\n                            {crumb.label}\n                          </BreadcrumbLink>\n                        ) : (\n                          <BreadcrumbPage>{crumb.label}</BreadcrumbPage>\n                        )}\n                      </BreadcrumbItem>\n                      {!isLast && <BreadcrumbSeparator />}\n                    </React.Fragment>\n                  );\n                })\n              ) : (\n                <BreadcrumbItem>\n                  <BreadcrumbPage>{pageName}</BreadcrumbPage>\n                </BreadcrumbItem>\n              )}\n            </BreadcrumbList>\n          </Breadcrumb>\n        </div>\n        <div className=\"flex items-center gap-2\">\n          {actions}\n          <DropdownMenu>\n            <DropdownMenuTrigger className=\"rounded-full outline-none focus-visible:ring-2 focus-visible:ring-sidebar-ring\">\n              <UserAvatar src={avatarSrc} name={userName} color={avatarColor} />\n            </DropdownMenuTrigger>\n            <DropdownMenuContent side=\"bottom\" align=\"end\" sideOffset={4}>\n              <UserMenuContent\n                src={avatarSrc}\n                name={userName}\n                email={userEmail}\n                color={avatarColor}\n                profileHref={profileHref}\n                onLogout={onLogout}\n                onShortcuts={() => setShortcutsOpen(true)}\n              />\n            </DropdownMenuContent>\n          </DropdownMenu>\n        </div>\n      </header>\n      <ShortcutsModal open={shortcutsOpen} onOpenChange={setShortcutsOpen} />\n    </>\n  );\n}\n\n// ─── Nav User (sidebar footer) ────────────────────────────────────────────────\nfunction SidebarNavUser({\n  user,\n  profileHref = '/profile',\n  onLogout,\n}: {\n  user?: SidebarUserInfo;\n  profileHref?: string;\n  onLogout?: () => void;\n}) {\n  const { isMobile } = useSidebar();\n  const userName = user?.name || 'User';\n  const userEmail = user?.email || 'user@example.com';\n  const avatarSrc = user?.avatar || '';\n  const avatarColor = getAvatarColor(userName);\n  const [shortcutsOpen, setShortcutsOpen] = useState(false);\n\n  return (\n    <>\n      <SidebarMenu>\n        <SidebarMenuItem>\n          <DropdownMenu>\n            <DropdownMenuTrigger asChild>\n              <SidebarMenuButton\n                size=\"lg\"\n                className=\"aria-expanded:bg-sidebar-accent\"\n              >\n                <UserAvatar\n                  src={avatarSrc}\n                  name={userName}\n                  color={avatarColor}\n                />\n                <div className=\"grid flex-1 text-left text-sm leading-tight group-data-[collapsible=icon]:hidden\">\n                  <span className=\"truncate font-medium\">{userName}</span>\n                  <span className=\"truncate text-xs text-muted-foreground\">\n                    {userEmail}\n                  </span>\n                </div>\n                <HugeiconsIcon\n                  icon={UnfoldMoreIcon}\n                  strokeWidth={2}\n                  className=\"ml-auto size-4 group-data-[collapsible=icon]:hidden\"\n                />\n              </SidebarMenuButton>\n            </DropdownMenuTrigger>\n            <DropdownMenuContent\n              side={isMobile ? 'bottom' : 'right'}\n              align=\"end\"\n              sideOffset={4}\n            >\n              <UserMenuContent\n                src={avatarSrc}\n                name={userName}\n                email={userEmail}\n                color={avatarColor}\n                profileHref={profileHref}\n                onLogout={onLogout}\n                onShortcuts={() => setShortcutsOpen(true)}\n              />\n            </DropdownMenuContent>\n          </DropdownMenu>\n        </SidebarMenuItem>\n      </SidebarMenu>\n      <ShortcutsModal open={shortcutsOpen} onOpenChange={setShortcutsOpen} />\n    </>\n  );\n}\n\n// ─── Section Group ────────────────────────────────────────────────────────────\nfunction SidebarSectionGroup({\n  section,\n  pathname,\n  collapsible,\n}: {\n  section: SidebarSection;\n  pathname: string;\n  collapsible: boolean;\n}) {\n  const [open, setOpen] = useState(true);\n\n  return (\n    <SidebarGroup>\n      <SidebarGroupLabel\n        className={cn(collapsible && 'cursor-pointer select-none')}\n        onClick={collapsible ? () => setOpen((v) => !v) : undefined}\n      >\n        <span className=\"flex-1\">{section.label}</span>\n        {collapsible && (\n          <HugeiconsIcon\n            icon={ArrowRight01Icon}\n            strokeWidth={2}\n            className={cn(\n              'size-3.5 shrink-0 text-sidebar-foreground/50 transition-transform duration-200',\n              open && 'rotate-90',\n            )}\n          />\n        )}\n      </SidebarGroupLabel>\n\n      <div\n        className={cn(\n          'grid transition-[grid-template-rows] duration-200 ease-in-out',\n          open ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]',\n        )}\n      >\n        <div className=\"overflow-hidden\">\n          <SidebarGroupContent>\n            <SidebarMenu>\n              {section.items.map((item) => {\n                const isActive = pathname === item.href;\n                const Icon = iconMap[item.icon];\n\n                return (\n                  <SidebarMenuItem key={item.href}>\n                    <SidebarMenuButton\n                      asChild\n                      isActive={isActive}\n                      tooltip={item.title}\n                    >\n                      <Link href={item.href}>\n                        {Icon && (\n                          <HugeiconsIcon\n                            icon={Icon}\n                            strokeWidth={2}\n                            className=\"size-4 shrink-0\"\n                          />\n                        )}\n                        <span>{item.title}</span>\n                      </Link>\n                    </SidebarMenuButton>\n                  </SidebarMenuItem>\n                );\n              })}\n            </SidebarMenu>\n          </SidebarGroupContent>\n        </div>\n      </div>\n    </SidebarGroup>\n  );\n}\n\n// ─── Main Sidebar ─────────────────────────────────────────────────────────────\nexport function AppShell1({\n  config = defaultConfig,\n  collapsibleSubsections = false,\n  user,\n  profileHref = '/profile',\n  onLogout,\n}: AppShell1Props) {\n  const pathname = usePathname();\n  const [searchOpen, setSearchOpen] = useState(false);\n  const { state } = useSidebar();\n  const isCollapsed = state === 'collapsed';\n\n  return (\n    <>\n      <Sidebar collapsible=\"icon\" variant=\"inset\">\n        {/* Company header + Search */}\n        <SidebarHeader>\n          <SidebarMenu>\n            <SidebarMenuItem>\n              <SidebarMenuButton size=\"lg\">\n                <Image\n                  src={config.company.logo || '/placeholder.png'}\n                  alt={config.company.name}\n                  width={32}\n                  height={32}\n                  className=\"flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground\"\n                />\n                <div className=\"flex flex-col gap-0.5 leading-none group-data-[collapsible=icon]:hidden\">\n                  <span className=\"text-sm font-semibold\">\n                    {config.company.name}\n                  </span>\n                  <span className=\"text-xs text-muted-foreground\">\n                    {config.company.subtitle}\n                  </span>\n                </div>\n              </SidebarMenuButton>\n            </SidebarMenuItem>\n          </SidebarMenu>\n\n          <SidebarMenu>\n            <SidebarMenuItem>\n              <SidebarMenuButton\n                onClick={() => setSearchOpen(true)}\n                variant=\"outline\"\n                tooltip=\"Search\"\n                className=\"border text-muted-foreground\"\n              >\n                <HugeiconsIcon\n                  icon={SearchIcon}\n                  strokeWidth={2}\n                  className=\"size-4 shrink-0\"\n                />\n                <span className=\"flex-1 group-data-[collapsible=icon]:hidden\">\n                  Search\n                </span>\n                {!isCollapsed && (\n                  <span className=\"ml-auto flex items-center gap-0.5 group-data-[collapsible=icon]:hidden\">\n                    <Kbd>⌘</Kbd>\n                    <Kbd>K</Kbd>\n                  </span>\n                )}\n              </SidebarMenuButton>\n            </SidebarMenuItem>\n          </SidebarMenu>\n        </SidebarHeader>\n\n        {/* Scrollable sections */}\n        <div className=\"relative flex min-h-0 flex-1 overflow-hidden pt-1\">\n          <div className=\"pointer-events-none absolute inset-x-0 top-0 z-10 h-4 bg-linear-to-b from-sidebar to-transparent\" />\n          <div className=\"pointer-events-none absolute inset-x-0 bottom-0 z-10 h-6 bg-linear-to-t from-sidebar to-transparent\" />\n\n          <SidebarContent>\n            {/* Standalone items */}\n            {config.items && config.items.length > 0 && (\n              <SidebarGroup>\n                <SidebarGroupContent>\n                  <SidebarMenu>\n                    {config.items.map((item) => {\n                      const isActive = pathname === item.href;\n                      const Icon = iconMap[item.icon];\n\n                      return (\n                        <SidebarMenuItem key={item.href}>\n                          <SidebarMenuButton\n                            asChild\n                            isActive={isActive}\n                            tooltip={item.title}\n                          >\n                            <Link href={item.href}>\n                              {Icon && (\n                                <HugeiconsIcon\n                                  icon={Icon}\n                                  strokeWidth={2}\n                                  className=\"size-4 shrink-0\"\n                                />\n                              )}\n                              <span>{item.title}</span>\n                            </Link>\n                          </SidebarMenuButton>\n                        </SidebarMenuItem>\n                      );\n                    })}\n                  </SidebarMenu>\n                </SidebarGroupContent>\n              </SidebarGroup>\n            )}\n\n            {/* Sectioned items */}\n            {config.sections.map((section) => (\n              <SidebarSectionGroup\n                key={section.label}\n                section={section}\n                pathname={pathname}\n                collapsible={collapsibleSubsections}\n              />\n            ))}\n          </SidebarContent>\n        </div>\n\n        <SidebarFooter>\n          <SidebarNavUser\n            user={user}\n            profileHref={profileHref}\n            onLogout={onLogout}\n          />\n        </SidebarFooter>\n        <SidebarRail />\n      </Sidebar>\n\n      <AppShell1Search\n        config={config}\n        open={searchOpen}\n        onOpenChange={setSearchOpen}\n      />\n    </>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/odysseyui/app-shell-1.tsx"
    },
    {
      "path": "registry/components/app-shells/app-shell-1/app-shell-1.config.ts",
      "content": "export interface SidebarMenuItem {\n  title: string;\n  href: string;\n  icon: string;\n  keywords?: string[];\n}\n\nexport interface SidebarSection {\n  label: string;\n  items: SidebarMenuItem[];\n}\n\nexport interface SidebarCompany {\n  name: string;\n  subtitle: string;\n  logo?: string;\n}\n\nexport interface AppShell1Config {\n  company: SidebarCompany;\n  items?: SidebarMenuItem[];\n  sections: SidebarSection[];\n}\n\nexport const appShell1Config: AppShell1Config = {\n  company: {\n    name: 'Acme Inc',\n    subtitle: 'Enterprise',\n    logo: '/templateImages/placeholder.png',\n  },\n  items: [\n    {\n      title: 'Dashboard',\n      href: '/dashboard',\n      icon: 'PieChart',\n      keywords: ['dashboard', 'overview'],\n    },\n  ],\n  sections: [\n    {\n      label: 'Platform',\n      items: [\n        {\n          title: 'Playground',\n          href: '/playground',\n          icon: 'SquareTerminal',\n          keywords: ['playground', 'terminal', 'code'],\n        },\n        {\n          title: 'Models',\n          href: '/models',\n          icon: 'Bot',\n          keywords: ['models', 'ai', 'machine learning'],\n        },\n        {\n          title: 'Documentation',\n          href: '/documentation',\n          icon: 'BookOpen',\n          keywords: ['docs', 'documentation', 'guides'],\n        },\n        {\n          title: 'Settings',\n          href: '/settings',\n          icon: 'Settings2',\n          keywords: ['settings', 'preferences', 'config'],\n        },\n      ],\n    },\n    {\n      label: 'Projects',\n      items: [\n        {\n          title: 'Design Engineering',\n          href: '/projects/design-engineering',\n          icon: 'Frame',\n          keywords: ['design', 'engineering', 'ui'],\n        },\n        {\n          title: 'Sales & Marketing',\n          href: '/projects/sales-marketing',\n          icon: 'PieChart',\n          keywords: ['sales', 'marketing', 'analytics'],\n        },\n        {\n          title: 'Travel',\n          href: '/projects/travel',\n          icon: 'Map',\n          keywords: ['travel', 'trips', 'locations'],\n        },\n      ],\n    },\n    {\n      label: 'Platform 2',\n      items: [\n        {\n          title: 'Playground',\n          href: '/playground',\n          icon: 'SquareTerminal',\n          keywords: ['playground', 'terminal', 'code'],\n        },\n        {\n          title: 'Models',\n          href: '/models',\n          icon: 'Bot',\n          keywords: ['models', 'ai', 'machine learning'],\n        },\n        {\n          title: 'Documentation',\n          href: '/documentation',\n          icon: 'BookOpen',\n          keywords: ['docs', 'documentation', 'guides'],\n        },\n        {\n          title: 'Settings',\n          href: '/settings',\n          icon: 'Settings2',\n          keywords: ['settings', 'preferences', 'config'],\n        },\n      ],\n    },\n    {\n      label: 'Projects 2',\n      items: [\n        {\n          title: 'Design Engineering',\n          href: '/projects/design-engineering',\n          icon: 'Frame',\n          keywords: ['design', 'engineering', 'ui'],\n        },\n        {\n          title: 'Sales & Marketing',\n          href: '/projects/sales-marketing',\n          icon: 'PieChart',\n          keywords: ['sales', 'marketing', 'analytics'],\n        },\n        {\n          title: 'Travel',\n          href: '/projects/travel',\n          icon: 'Map',\n          keywords: ['travel', 'trips', 'locations'],\n        },\n      ],\n    },\n  ],\n};\n",
      "type": "registry:ui",
      "target": "components/odysseyui/app-shell-1.config.ts"
    }
  ],
  "type": "registry:ui"
}