{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "dashboard-layout",
  "title": "Dashboard Layout",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-svelte/blocks/dashboard-layout/DashboardLayout.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n\n  export interface DashboardLayoutCrumb {\n    label: string\n    href?: string\n  }\n\n  export interface DashboardLayoutProps {\n    breadcrumbs?: DashboardLayoutCrumb[]\n    user?: { name: string; email: string; avatar?: string }\n    onProfileSelect?: (key: string) => void\n    onCommandSelect?: (item: { label: string; hint?: string }) => void\n    children?: Snippet\n  }\n</script>\n\n<script lang=\"ts\">\n  import { Bell } from '@lucide/svelte'\n  import Sidebar02 from '$lib/components/blocks/sidebar-02/Sidebar02.svelte'\n  import CommandPalette from '$lib/components/blocks/command-palette/CommandPalette.svelte'\n  import NotificationsPopover from '$lib/components/blocks/notifications-popover/NotificationsPopover.svelte'\n  import { Button } from '$lib/components/ui/button'\n  import { Separator } from '$lib/components/ui/separator'\n  import {\n    Breadcrumb,\n    BreadcrumbItem,\n    BreadcrumbLink,\n    BreadcrumbList,\n    BreadcrumbPage,\n    BreadcrumbSeparator,\n  } from '$lib/components/ui/breadcrumb'\n  import { SidebarInset, SidebarProvider, SidebarTrigger } from '$lib/components/ui/sidebar'\n  import { ThemeSwitch, type ThemeSwitchTheme } from '$lib/components/ui/theme-switch'\n\n  let {\n    breadcrumbs = [{ label: 'Dashboard' }],\n    user = { name: 'Alex Morgan', email: 'alex@example.com' },\n    onProfileSelect,\n    onCommandSelect,\n    children,\n  }: DashboardLayoutProps = $props()\n\n  // The Svelte registry ships no use-theme hook (yet), so the shell owns a\n  // tiny local theme state and applies the dark class itself. Swap this for\n  // your own theme store after install.\n  type Theme = 'light' | 'dark' | 'system'\n  let theme = $state<Theme>('system')\n\n  $effect(() => {\n    const root = document.documentElement\n    const dark = theme === 'dark' || (theme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches)\n    root.classList.toggle('dark', dark)\n  })\n\n  // ThemeSwitch can emit 'black' but this shell only models light/dark/system;\n  // fall back to dark so the control still works in this block.\n  function onThemeChange(t: ThemeSwitchTheme) {\n    theme = t === 'black' ? 'dark' : t\n  }\n\n  // `user` + `onProfileSelect` are accepted for API parity with the Vue twin\n  // (consumers wire them into NavUser or a custom header slot) but intentionally\n  // unused here: the header shows no avatar because the sidebar-02 footer's\n  // NavUser already owns the profile affordance.\n</script>\n\n<SidebarProvider data-slot=\"dashboard-layout\">\n  <a\n    href=\"#main-content\"\n    class=\"bg-background text-foreground ring-ring sr-only z-50 rounded-md text-sm font-medium shadow-md ring-2 focus:not-sr-only focus:fixed focus:top-2 focus:left-2 focus:px-3 focus:py-2\"\n    >Skip to content</a\n  >\n  <Sidebar02 />\n  <SidebarInset>\n    <header\n      class=\"bg-background/80 supports-[backdrop-filter]:bg-background/60 sticky top-0 z-30 flex h-14 w-full shrink-0 items-center justify-between border-b px-4 backdrop-blur-xl transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12\"\n    >\n      <div class=\"flex items-center gap-2\">\n        <SidebarTrigger class=\"-ml-1\" />\n        <Separator orientation=\"vertical\" class=\"mr-2 h-4\" />\n        <Breadcrumb>\n          <BreadcrumbList>\n            {#each breadcrumbs as crumb, i (i)}\n              <BreadcrumbItem class={i === 0 ? 'hidden md:block' : ''}>\n                {#if crumb.href && i < breadcrumbs.length - 1}\n                  <BreadcrumbLink\n                    href={crumb.href}\n                    class=\"text-muted-foreground/70 hover:text-foreground transition-colors\"\n                  >\n                    {crumb.label}\n                  </BreadcrumbLink>\n                {:else}\n                  <BreadcrumbPage class=\"font-medium\">{crumb.label}</BreadcrumbPage>\n                {/if}\n              </BreadcrumbItem>\n              {#if i < breadcrumbs.length - 1}\n                <BreadcrumbSeparator class={i === 0 ? 'hidden md:block' : ''} />\n              {/if}\n            {/each}\n          </BreadcrumbList>\n        </Breadcrumb>\n      </div>\n      <div class=\"flex items-center gap-1 px-2 sm:gap-3\">\n        <CommandPalette onSelect={(item) => onCommandSelect?.(item)} />\n        <div class=\"flex items-center gap-0.5\">\n          <ThemeSwitch value={theme} variant=\"icon-only\" onValueChange={onThemeChange} />\n          <NotificationsPopover>\n            {#snippet children({ props, unreadCount })}\n              <Button\n                {...props}\n                variant=\"ghost\"\n                size=\"icon\"\n                class=\"text-muted-foreground hover:text-foreground relative size-8 rounded-lg\"\n                aria-label=\"Notifications\"\n              >\n                <Bell class=\"size-4\" />\n                {#if unreadCount > 0}\n                  <span\n                    class=\"bg-primary ring-background absolute top-1.5 right-1.5 size-2 rounded-full ring-2\"\n                  ></span>\n                {/if}\n              </Button>\n            {/snippet}\n          </NotificationsPopover>\n          <!-- ProfileMenu removed from header: the sidebar's NavUser\n               (sidebar-02 footer) already owns the profile/account\n               affordance. Two avatars in the same screen pulled the\n               eye in conflicting directions. The block still accepts\n               a `user` prop + `onProfileSelect` so consumers can\n               wire those into NavUser or a custom header slot. -->\n        </div>\n      </div>\n    </header>\n    <main id=\"main-content\" tabindex=\"-1\" class=\"flex flex-1 flex-col px-4 pt-4 pb-4 outline-none lg:px-6 lg:pt-6 lg:pb-6\">\n      {@render children?.()}\n    </main>\n  </SidebarInset>\n</SidebarProvider>\n",
      "type": "registry:block",
      "target": "~/src/lib/components/blocks/dashboard-layout/DashboardLayout.svelte"
    }
  ],
  "dependencies": [
    "@lucide/svelte"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/svelte/sidebar-02.json",
    "https://uipkge.dev/r/svelte/command-palette.json",
    "https://uipkge.dev/r/svelte/notifications-popover.json",
    "https://uipkge.dev/r/svelte/theme-switch.json",
    "https://uipkge.dev/r/svelte/sidebar.json",
    "https://uipkge.dev/r/svelte/breadcrumb.json",
    "https://uipkge.dev/r/svelte/button.json",
    "https://uipkge.dev/r/svelte/separator.json"
  ],
  "description": "Full dashboard shell — collapsible sidebar (sidebar-02) + sticky topbar (sidebar trigger, breadcrumb, command palette, theme switch, notifications, profile menu) + main content slot. Drop it in a SvelteKit layout: `<DashboardLayout>{@render children?.()}</DashboardLayout>`. Auto-pulls every transitive piece (sidebar-02, command-palette, notifications-popover, profile-menu, theme-switch).",
  "categories": [
    "layout",
    "dashboard"
  ]
}