{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "page-layouts-03",
  "type": "registry:component",
  "title": "Page Layouts",
  "author": "Toby Belhome",
  "description": "Design organized and intuitive dashboard experiences with Tailwind CSS page layouts. These sections combine sidebars, headers, content areas, and responsive grids to present data clearly. Perfect for SaaS platforms, admin panels, and analytics tools seeking modern, user-friendly, and visually structured interfaces.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "sidebar",
    "separator",
    "button",
    "collapsible",
    "avatar",
    "button",
    "toggle",
    "sidebar"
  ],
  "files": [
    {
      "path": "examples/blocks/dashboard-ui/page-layouts/03/components/app-header.tsx",
      "content": "import * as React from \"react\";\n\nimport { SidebarTrigger } from \"@/components/ui/sidebar\";\nimport { Separator } from \"@/components/ui/separator\";\n\nimport { NavMainHorizontal } from \"./nav-main-horizontal\";\nimport { navigationLinks } from \"./app-sidebar\";\nimport { NavUser } from \"./nav-user\";\nimport { Logo } from \"./logo\";\nimport { BellIcon, MailIcon } from \"lucide-react\";\nimport { Button } from \"@/components/ui/button\";\nimport ThemeToggle from \"./theme-toggle\";\n\nexport function AppHeader() {\n  return (\n    <header\n      data-slot=\"header\"\n      className=\"flex h-16 shrink-0 items-center justify-between gap-2 px-4 [&_[data-logo=description]]:hidden\">\n      <div className=\"flex grow items-center\">\n        <Logo />\n        <Separator orientation=\"vertical\" className=\"mx-4 data-[orientation=vertical]:h-4\" />\n        <SidebarTrigger className=\"-ml-1 md:hidden\" />\n        <NavMainHorizontal items={navigationLinks} />\n      </div>\n      <div className=\"flex items-center gap-6\">\n        <div className=\"flex items-center gap-2\">\n          <ThemeToggle />\n          <Button size=\"icon-sm\" variant=\"ghost\" className=\"relative\">\n            <MailIcon />\n            <span className=\"bg-foreground absolute end-0 top-0 inline size-1.5 rounded-full\" />\n          </Button>\n          <Button size=\"icon-sm\" variant=\"ghost\" className=\"relative\">\n            <BellIcon />\n            <span className=\"bg-foreground absolute end-0 top-0 inline size-1.5 rounded-full\" />\n          </Button>\n        </div>\n        <NavUser />\n      </div>\n    </header>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/page-layouts/components/app-header.tsx"
    },
    {
      "path": "examples/blocks/dashboard-ui/page-layouts/03/components/app-sidebar.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { BookOpenIcon, InfoIcon, LifeBuoyIcon } from \"lucide-react\";\n\nimport {\n  Sidebar,\n  SidebarContent,\n  SidebarHeader,\n  SidebarMenu,\n  SidebarMenuButton,\n  SidebarMenuItem\n} from \"@/components/ui/sidebar\";\nimport { NavMainVertical } from \"./nav-main-vertical\";\nimport { useIsMobile } from \"@/hooks/use-mobile\";\nimport { Logo } from \"./logo\";\n\nexport const navigationLinks = [\n  {\n    title: \"Get Started\",\n    type: \"description\",\n    isActive: true,\n    items: [\n      {\n        url: \"#\",\n        title: \"Dashboard\",\n        description: \"Browse all components in the library.\"\n      },\n      {\n        url: \"#\",\n        title: \"Ecommerce\",\n        description: \"Learn how to use the library.\"\n      },\n      {\n        url: \"#\",\n        title: \"Reports\",\n        description: \"Pre-built layouts for common use cases.\"\n      }\n    ]\n  },\n  {\n    title: \"Apps\",\n    type: \"simple\",\n    items: [\n      { url: \"#\", title: \"Chats\" },\n      { url: \"#\", title: \"Kanban Board\" },\n      { url: \"#\", title: \"Notes\" },\n      { url: \"#\", title: \"Event Calendar\" }\n    ]\n  },\n  {\n    title: \"Pages\",\n    type: \"icon\",\n    items: [\n      { url: \"#\", title: \"Profile Page\", icon: BookOpenIcon },\n      { url: \"#\", title: \"User List\", icon: LifeBuoyIcon },\n      { url: \"#\", title: \"Pricing Page\", icon: InfoIcon }\n    ]\n  }\n];\n\nexport function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {\n  const isMobile = useIsMobile();\n\n  if (!isMobile) return null;\n\n  return (\n    <Sidebar variant=\"inset\" {...props}>\n      <SidebarHeader>\n        <SidebarMenu>\n          <SidebarMenuItem>\n            <SidebarMenuButton size=\"lg\" asChild>\n              <Logo />\n            </SidebarMenuButton>\n          </SidebarMenuItem>\n        </SidebarMenu>\n      </SidebarHeader>\n      <SidebarContent>\n        <NavMainVertical items={navigationLinks} />\n      </SidebarContent>\n    </Sidebar>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/page-layouts/components/app-sidebar.tsx"
    },
    {
      "path": "examples/blocks/dashboard-ui/page-layouts/03/components/logo.tsx",
      "content": "import * as React from \"react\";\nimport Link from \"next/link\";\n\nexport function Logo() {\n  return (\n    <Link href=\"#\" className=\"flex gap-3\">\n      <img src=\"https://shadcnuikit.com/logo.png\" className=\"size-8 rounded-md\" alt=\"\" />\n      <div\n        data-logo=\"description\"\n        className=\"grid flex-1 text-left text-sm leading-tight md:hidden\">\n        <span className=\"truncate font-medium\">Acme Inc</span>\n        <span className=\"truncate text-xs\">Enterprise</span>\n      </div>\n    </Link>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/page-layouts/components/logo.tsx"
    },
    {
      "path": "examples/blocks/dashboard-ui/page-layouts/03/components/nav-main-horizontal.tsx",
      "content": "\"use client\";\n\nimport { type LucideIcon } from \"lucide-react\";\nimport {\n  NavigationMenu,\n  NavigationMenuContent,\n  NavigationMenuItem,\n  NavigationMenuLink,\n  NavigationMenuList,\n  NavigationMenuTrigger\n} from \"@/components/ui/navigation-menu\";\nimport { cn } from \"@/lib/utils\";\n\nexport function NavMainHorizontal({\n  items\n}: {\n  items: {\n    title: string;\n    type: string;\n    url?: string;\n    icon?: LucideIcon;\n    isActive?: boolean;\n    items?: {\n      title: string;\n      url: string;\n      description?: string;\n      icon?: LucideIcon;\n      isActive?: boolean;\n    }[];\n  }[];\n}) {\n  return (\n    <NavigationMenu viewport={false} className=\"max-md:hidden\">\n      <NavigationMenuList className=\"gap-2\">\n        {items.map((link, index) => (\n          <NavigationMenuItem key={index}>\n            {link.items?.length ? (\n              <>\n                <NavigationMenuTrigger className=\"text-muted-foreground hover:text-primary border-y-2 border-y-transparent bg-transparent px-2 py-1.5 font-medium *:[svg]:-me-0.5 *:[svg]:size-3.5\">\n                  {link.title}\n                  {link.isActive && (\n                    <div className=\"bg-primary absolute start-2 end-2 -bottom-4 h-0.5\"></div>\n                  )}\n                </NavigationMenuTrigger>\n                <NavigationMenuContent className=\"data-[motion=from-end]:slide-in-from-right-16! data-[motion=from-start]:slide-in-from-left-16! data-[motion=to-end]:slide-out-to-right-16! data-[motion=to-start]:slide-out-to-left-16! z-50 p-1\">\n                  <ul className={cn(link.type === \"description\" ? \"min-w-64\" : \"min-w-48\")}>\n                    {link.items.map((item, itemIndex) => (\n                      <li key={itemIndex}>\n                        <NavigationMenuLink href={item.url} className=\"py-1.5\">\n                          {/* Display icon if present */}\n                          {link.type === \"icon\" && \"icon\" in item && (\n                            <div className=\"flex items-center gap-2\">\n                              {item.icon && (\n                                <item.icon\n                                  size={16}\n                                  className=\"text-foreground opacity-60\"\n                                  aria-hidden=\"true\"\n                                />\n                              )}\n                              <span>{item.title}</span>\n                            </div>\n                          )}\n\n                          {/* Display label with description if present */}\n                          {link.type === \"description\" && \"description\" in item ? (\n                            <div className=\"space-y-1\">\n                              <div className=\"font-medium\">{item.title}</div>\n                              <p className=\"text-muted-foreground line-clamp-2 text-xs\">\n                                {item.description}\n                              </p>\n                            </div>\n                          ) : (\n                            // Display simple label if not icon or description type\n                            !link.type ||\n                            (link.type !== \"icon\" && link.type !== \"description\" && (\n                              <span>{item.title}</span>\n                            ))\n                          )}\n                        </NavigationMenuLink>\n                      </li>\n                    ))}\n                  </ul>\n                </NavigationMenuContent>\n              </>\n            ) : (\n              <NavigationMenuLink\n                href={link.url}\n                className=\"text-muted-foreground hover:text-primary py-1.5 font-medium\">\n                {link.title}\n              </NavigationMenuLink>\n            )}\n          </NavigationMenuItem>\n        ))}\n      </NavigationMenuList>\n    </NavigationMenu>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/page-layouts/components/nav-main-horizontal.tsx"
    },
    {
      "path": "examples/blocks/dashboard-ui/page-layouts/03/components/nav-main-vertical.tsx",
      "content": "\"use client\";\n\nimport { ChevronRight, type LucideIcon } from \"lucide-react\";\n\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } 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 \"@/components/ui/sidebar\";\n\nexport function NavMainVertical({\n  items\n}: {\n  items: {\n    title: string;\n    type: string;\n    url?: string;\n    icon?: LucideIcon;\n    items?: {\n      title: string;\n      url: string;\n      description?: string;\n      icon?: LucideIcon;\n    }[];\n  }[];\n}) {\n  return (\n    <>\n      {items.map((item, i) => (\n        <SidebarGroup>\n          <SidebarGroupLabel>{item.title}</SidebarGroupLabel>\n          <SidebarMenu>\n            {item.items?.length ? (\n              <>\n                {item.items?.map((subItem) => (\n                  <SidebarMenuItem key={subItem.title}>\n                    <SidebarMenuButton asChild>\n                      <a href={subItem.url}>\n                        <span>{subItem.title}</span>\n                      </a>\n                    </SidebarMenuButton>\n                  </SidebarMenuItem>\n                ))}\n              </>\n            ) : null}\n          </SidebarMenu>\n        </SidebarGroup>\n      ))}\n    </>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/page-layouts/components/nav-main-vertical.tsx"
    },
    {
      "path": "examples/blocks/dashboard-ui/page-layouts/03/components/nav-projects.tsx",
      "content": "\"use client\";\n\nimport { type LucideIcon } from \"lucide-react\";\n\nimport {\n  SidebarGroup,\n  SidebarGroupLabel,\n  SidebarMenu,\n  SidebarMenuButton,\n  SidebarMenuItem\n} from \"@/components/ui/sidebar\";\nimport Link from \"next/link\";\n\nexport function NavProjects({\n  projects\n}: {\n  projects: {\n    name: string;\n    url: string;\n    icon: LucideIcon;\n  }[];\n}) {\n  return (\n    <SidebarGroup className=\"group-data-[collapsible=icon]:hidden\">\n      <SidebarGroupLabel>Projects</SidebarGroupLabel>\n      <SidebarMenu>\n        {projects.map((item) => (\n          <SidebarMenuItem key={item.name}>\n            <SidebarMenuButton asChild>\n              <Link href={item.url}>\n                <item.icon />\n                <span>{item.name}</span>\n              </Link>\n            </SidebarMenuButton>\n          </SidebarMenuItem>\n        ))}\n      </SidebarMenu>\n    </SidebarGroup>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/page-layouts/components/nav-projects.tsx"
    },
    {
      "path": "examples/blocks/dashboard-ui/page-layouts/03/components/nav-user.tsx",
      "content": "\"use client\";\n\nimport { BadgeCheck, Bell, CreditCard, LogOut, Sparkles } from \"lucide-react\";\n\nimport { Avatar, AvatarFallback, AvatarImage } 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 { Button } from \"@/components/ui/button\";\n\nconst user = {\n  name: \"shadcn\",\n  email: \"m@example.com\",\n  avatar: \"https://ui.shadcn.com/avatars/shadcn.jpg\"\n};\n\nexport function NavUser() {\n  return (\n    <DropdownMenu>\n      <DropdownMenuTrigger asChild>\n        <Button variant=\"ghost\" className=\"p-0\">\n          <Avatar>\n            <AvatarImage src={user.avatar} alt={user.name} />\n            <AvatarFallback className=\"rounded-lg\">CN</AvatarFallback>\n          </Avatar>\n        </Button>\n      </DropdownMenuTrigger>\n      <DropdownMenuContent className=\"min-w-56 rounded-lg\" align=\"end\" sideOffset={4}>\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 className=\"rounded-lg\">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        <DropdownMenuSeparator />\n        <DropdownMenuGroup>\n          <DropdownMenuItem>\n            <Sparkles />\n            Upgrade to Pro\n          </DropdownMenuItem>\n        </DropdownMenuGroup>\n        <DropdownMenuSeparator />\n        <DropdownMenuGroup>\n          <DropdownMenuItem>\n            <BadgeCheck />\n            Account\n          </DropdownMenuItem>\n          <DropdownMenuItem>\n            <CreditCard />\n            Billing\n          </DropdownMenuItem>\n          <DropdownMenuItem>\n            <Bell />\n            Notifications\n          </DropdownMenuItem>\n        </DropdownMenuGroup>\n        <DropdownMenuSeparator />\n        <DropdownMenuItem>\n          <LogOut />\n          Log out\n        </DropdownMenuItem>\n      </DropdownMenuContent>\n    </DropdownMenu>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/page-layouts/components/nav-user.tsx"
    },
    {
      "path": "examples/blocks/dashboard-ui/page-layouts/03/components/theme-toggle.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { MoonIcon, SunIcon } from \"lucide-react\";\n\nimport { Toggle } from \"@/components/ui/toggle\";\n\nexport default function ThemeToggle() {\n  const [theme, setTheme] = useState<string>(\"light\");\n\n  return (\n    <div>\n      <Toggle\n        variant=\"outline\"\n        className=\"group text-muted-foreground data-[state=on]:text-muted-foreground data-[state=on]:hover:bg-muted data-[state=on]:hover:text-foreground size-8 rounded-full border-none shadow-none data-[state=on]:bg-transparent\"\n        pressed={theme === \"dark\"}\n        onPressedChange={() => setTheme((prev) => (prev === \"dark\" ? \"light\" : \"dark\"))}\n        aria-label={`Switch to ${theme === \"dark\" ? \"light\" : \"dark\"} mode`}>\n        {/* Note: After dark mode implementation, rely on dark: prefix rather than group-data-[state=on]: */}\n        <MoonIcon\n          size={16}\n          className=\"shrink-0 scale-0 opacity-0 transition-all group-data-[state=on]:scale-100 group-data-[state=on]:opacity-100\"\n          aria-hidden=\"true\"\n        />\n        <SunIcon\n          size={16}\n          className=\"absolute shrink-0 scale-100 opacity-100 transition-all group-data-[state=on]:scale-0 group-data-[state=on]:opacity-0\"\n          aria-hidden=\"true\"\n        />\n      </Toggle>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/page-layouts/components/theme-toggle.tsx"
    },
    {
      "path": "examples/blocks/dashboard-ui/page-layouts/03/page.tsx",
      "content": "import { SidebarInset, SidebarProvider } from \"@/components/ui/sidebar\";\n\nimport { AppSidebar } from \"./components/app-sidebar\";\nimport { AppHeader } from \"./components/app-header\";\n\nexport default function Page() {\n  return (\n    <SidebarProvider>\n      <AppSidebar />\n      <SidebarInset className=\"bg-muted/50\">\n        <AppHeader />\n        <div className=\"flex flex-1 flex-col gap-4 p-4 pt-0\">\n          <div className=\"bg-background grid min-h-[100vh] flex-1 place-items-center rounded-xl md:min-h-min\">\n            <span className=\"text-muted-foreground text-sm\">Content goes here</span>\n          </div>\n        </div>\n      </SidebarInset>\n    </SidebarProvider>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/page-layouts/page-layouts.tsx"
    }
  ],
  "meta": {
    "isPro": true
  }
}