{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "app-shell-1",
  "description": "An application shell with a sidebar, top bar, and content area.",
  "dependencies": [
    "@remixicon/react",
    "@base-ui/react"
  ],
  "registryDependencies": [
    "avatar",
    "badge",
    "button",
    "command",
    "dropdown-menu",
    "kbd",
    "popover",
    "progress",
    "separator",
    "sidebar"
  ],
  "files": [
    {
      "path": "registry/blocks/app-shell/1/app-shell-block.tsx",
      "content": "\"use client\"\n\nimport {\n  RiHome5Line,\n  RiLayoutGridLine,\n  RiBarChartBoxLine,\n  RiUserLine,\n  RiSettings3Line,\n  RiNotification3Line,\n  RiArrowUpLine,\n  RiArrowDownLine,\n  RiMoreLine,\n  RiCheckboxCircleLine,\n  RiTimeLine,\n  RiFileTextLine,\n  RiUser3Line,\n  RiLogoutBoxRLine,\n  RiPaletteLine,\n  RiGlobalLine,\n  RiShieldUserLine,\n  RiChat3Line,\n  RiErrorWarningLine,\n  RiSearchLine,\n} from \"@remixicon/react\"\n\nimport * as React from \"react\"\nimport type { ReactElement } from \"react\"\n\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/components/ui/avatar\"\nimport { Button } from \"@/components/ui/button\"\nimport { Badge } from \"@/components/ui/badge\"\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n} from \"@/components/ui/popover\"\nimport { Separator } from \"@/components/ui/separator\"\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\"\nimport {\n  Command,\n  CommandDialog,\n  CommandEmpty,\n  CommandGroup,\n  CommandInput,\n  CommandItem,\n  CommandList,\n} from \"@/components/ui/command\"\nimport { Kbd, KbdGroup } from \"@/components/ui/kbd\"\nimport {\n  Progress,\n  ProgressLabel,\n  ProgressValue,\n} from \"@/components/ui/progress\"\nimport {\n  Sidebar,\n  SidebarContent,\n  SidebarFooter,\n  SidebarGroup,\n  SidebarGroupContent,\n  SidebarGroupLabel,\n  SidebarHeader,\n  SidebarInset,\n  SidebarMenu,\n  SidebarMenuButton,\n  SidebarMenuItem,\n  SidebarProvider,\n  SidebarTrigger,\n} from \"@/components/ui/sidebar\"\n\nconst navItems = [\n  { label: \"Dashboard\", icon: RiHome5Line, active: true },\n  { label: \"Projects\", icon: RiLayoutGridLine, active: false },\n  { label: \"Analytics\", icon: RiBarChartBoxLine, active: false },\n  { label: \"Team\", icon: RiUserLine, active: false },\n  { label: \"Settings\", icon: RiSettings3Line, active: false },\n]\n\nconst workspaces = [\n  { label: \"Design System\", icon: RiPaletteLine },\n  { label: \"Marketing Site\", icon: RiGlobalLine },\n  { label: \"Admin Panel\", icon: RiShieldUserLine },\n]\n\nconst navCommands = [\n  ...navItems.map((item) => ({\n    label: `Go to ${item.label}`,\n    icon: item.icon,\n  })),\n  ...workspaces.map((ws) => ({ label: `Open ${ws.label}`, icon: ws.icon })),\n]\n\nconst actionCommands = [\n  { label: \"Invite a teammate\", icon: RiUser3Line },\n  { label: \"View notifications\", icon: RiNotification3Line },\n]\n\nconst stats = [\n  { label: \"Total revenue\", value: \"$48,240\", delta: \"+12.5%\", positive: true },\n  { label: \"Active users\", value: \"8,941\", delta: \"+4.3%\", positive: true },\n  { label: \"Conversion\", value: \"3.24%\", delta: \"-0.8%\", positive: false },\n]\n\nconst currentUser = {\n  name: \"Alex Morton\",\n  initials: \"AM\",\n  email: \"alex@acme.com\",\n  avatar: \"https://i.pravatar.cc/150?img=12\",\n}\n\nconst activity = [\n  {\n    id: 1,\n    user: \"Sofia Reyes\",\n    initials: \"SR\",\n    avatar: \"https://i.pravatar.cc/150?img=45\",\n    action: \"Closed issue\",\n    target: \"Payment gateway timeout\",\n    time: \"2 Min Ago\",\n    icon: RiCheckboxCircleLine,\n  },\n  {\n    id: 2,\n    user: \"James Okafor\",\n    initials: \"JO\",\n    avatar: \"https://i.pravatar.cc/150?img=33\",\n    action: \"Updated report\",\n    target: \"Q2 Revenue Summary\",\n    time: \"18 Min Ago\",\n    icon: RiFileTextLine,\n  },\n  {\n    id: 3,\n    user: \"Mia Chen\",\n    initials: \"MC\",\n    avatar: \"https://i.pravatar.cc/150?img=20\",\n    action: \"Scheduled review\",\n    target: \"Infrastructure audit\",\n    time: \"1 Hour Ago\",\n    icon: RiTimeLine,\n  },\n  {\n    id: 4,\n    user: \"Daniel Park\",\n    initials: \"DP\",\n    avatar: \"https://i.pravatar.cc/150?img=53\",\n    action: \"Closed issue\",\n    target: \"Dashboard cache miss\",\n    time: \"3 Hours Ago\",\n    icon: RiCheckboxCircleLine,\n  },\n]\n\nconst projects = [\n  { name: \"Horizon Rebrand\", progress: 72, status: \"On Track\" },\n  { name: \"API v3 Migration\", progress: 38, status: \"At Risk\" },\n  { name: \"Mobile App Launch\", progress: 91, status: \"On Track\" },\n]\n\nconst initialNotifications = [\n  {\n    id: 1,\n    icon: RiChat3Line,\n    title: \"Sofia Reyes commented on Payment gateway timeout\",\n    time: \"2 Min Ago\",\n    unread: true,\n  },\n  {\n    id: 2,\n    icon: RiCheckboxCircleLine,\n    title: \"Deploy to production succeeded\",\n    time: \"1 Hour Ago\",\n    unread: true,\n  },\n  {\n    id: 3,\n    icon: RiErrorWarningLine,\n    title: \"API v3 Migration was flagged at risk\",\n    time: \"3 Hours Ago\",\n    unread: false,\n  },\n]\n\nfunction NotificationsMenu() {\n  const [items, setItems] = React.useState(initialNotifications)\n  const unread = items.filter((n) => n.unread).length\n\n  const markAllRead = () =>\n    setItems((prev) => prev.map((n) => ({ ...n, unread: false })))\n\n  return (\n    <Popover>\n      <PopoverTrigger\n        render={<Button variant=\"outline\" size=\"icon\" className=\"relative\" />}\n        aria-label=\"Notifications\"\n      >\n        <RiNotification3Line aria-hidden=\"true\" />\n        {unread > 0 && (\n          <span\n            className=\"absolute top-1 right-1 size-1.5 bg-primary\"\n            aria-hidden=\"true\"\n          />\n        )}\n      </PopoverTrigger>\n      <PopoverContent\n        align=\"end\"\n        sideOffset={8}\n        className=\"w-[320px] gap-0 p-0\"\n      >\n        <div className=\"flex items-center justify-between px-4 py-3\">\n          <div className=\"flex items-center gap-2\">\n            <span className=\"text-sm font-semibold tracking-tight\">\n              Notifications\n            </span>\n            {unread > 0 && (\n              <Badge\n                variant=\"secondary\"\n                className=\"h-5 px-1.5 text-[10px] font-medium\"\n              >\n                {unread} New\n              </Badge>\n            )}\n          </div>\n          <Button\n            variant=\"ghost\"\n            size=\"xs\"\n            className=\"text-xs text-muted-foreground hover:text-foreground\"\n            onClick={markAllRead}\n            disabled={unread === 0}\n          >\n            Mark all read\n          </Button>\n        </div>\n\n        <Separator />\n\n        <ul className=\"flex flex-col\">\n          {items.map((item, index) => (\n            <li key={item.id}>\n              <div\n                className={[\n                  \"flex items-start gap-3 px-4 py-3 transition-colors hover:bg-muted/40\",\n                  item.unread ? \"bg-muted/30\" : \"\",\n                ]\n                  .filter(Boolean)\n                  .join(\" \")}\n              >\n                <span className=\"mt-0.5 flex size-7 shrink-0 items-center justify-center bg-muted text-muted-foreground\">\n                  <item.icon className=\"size-3.5\" aria-hidden=\"true\" />\n                </span>\n                <div className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n                  <p\n                    className={[\n                      \"text-xs leading-snug\",\n                      item.unread\n                        ? \"font-medium text-foreground\"\n                        : \"text-foreground/80\",\n                    ].join(\" \")}\n                  >\n                    {item.title}\n                  </p>\n                  <span className=\"text-[10px] text-muted-foreground tabular-nums\">\n                    {item.time}\n                  </span>\n                </div>\n                {item.unread && (\n                  <span\n                    className=\"mt-1 size-1.5 shrink-0 bg-primary\"\n                    aria-label=\"Unread\"\n                  />\n                )}\n              </div>\n              {index < items.length - 1 && <Separator />}\n            </li>\n          ))}\n        </ul>\n\n        <Separator />\n\n        <div className=\"px-4 py-2.5 text-center\">\n          <Button\n            variant=\"link\"\n            size=\"sm\"\n            className=\"h-auto p-0 text-xs text-muted-foreground hover:text-foreground\"\n            render={<a href=\"#\" />}\n            nativeButton={false}\n          >\n            View all notifications\n          </Button>\n        </div>\n      </PopoverContent>\n    </Popover>\n  )\n}\n\nfunction UserMenu({\n  trigger,\n  align = \"start\",\n}: {\n  trigger: ReactElement\n  align?: \"start\" | \"end\"\n}) {\n  return (\n    <DropdownMenu>\n      <DropdownMenuTrigger render={trigger} />\n      <DropdownMenuContent align={align} className=\"w-44\">\n        <div className=\"flex flex-col gap-0.5 px-2 py-1.5\">\n          <p className=\"truncate text-xs font-semibold text-foreground\">\n            {currentUser.name}\n          </p>\n          <p className=\"truncate text-[10px] text-muted-foreground\">\n            {currentUser.email}\n          </p>\n        </div>\n        <DropdownMenuSeparator />\n        <DropdownMenuItem>\n          <RiUser3Line aria-hidden=\"true\" />\n          Account\n        </DropdownMenuItem>\n        <DropdownMenuItem>\n          <RiSettings3Line aria-hidden=\"true\" />\n          Settings\n        </DropdownMenuItem>\n        <DropdownMenuSeparator />\n        <DropdownMenuItem variant=\"destructive\">\n          <RiLogoutBoxRLine aria-hidden=\"true\" />\n          Log Out\n        </DropdownMenuItem>\n      </DropdownMenuContent>\n    </DropdownMenu>\n  )\n}\n\nexport default function AppShellBlock() {\n  const [commandOpen, setCommandOpen] = React.useState(false)\n\n  React.useEffect(() => {\n    function onKeyDown(event: KeyboardEvent) {\n      if (event.key === \"k\" && (event.metaKey || event.ctrlKey)) {\n        event.preventDefault()\n        setCommandOpen((open) => !open)\n      }\n    }\n    document.addEventListener(\"keydown\", onKeyDown)\n    return () => document.removeEventListener(\"keydown\", onKeyDown)\n  }, [])\n\n  return (\n    <SidebarProvider defaultOpen className=\"min-h-svh\">\n      <Sidebar collapsible=\"icon\">\n        <SidebarHeader>\n          <div className=\"flex h-10 items-center gap-2.5 px-2\">\n            <svg\n              viewBox=\"0 0 24 24\"\n              fill=\"currentColor\"\n              aria-hidden=\"true\"\n              className=\"size-5 shrink-0 text-foreground\"\n            >\n              <rect\n                x=\"3\"\n                y=\"3\"\n                width=\"8\"\n                height=\"8\"\n                transform=\"rotate(-6 7 7)\"\n              />\n              <rect\n                x=\"3\"\n                y=\"13\"\n                width=\"8\"\n                height=\"8\"\n                transform=\"rotate(5 7 17)\"\n              />\n              <rect\n                x=\"13\"\n                y=\"13\"\n                width=\"8\"\n                height=\"8\"\n                transform=\"rotate(-4 17 17)\"\n              />\n              <rect\n                x=\"13\"\n                y=\"3\"\n                width=\"8\"\n                height=\"8\"\n                transform=\"rotate(15 17 7)\"\n              />\n            </svg>\n            <span className=\"font-bold tracking-tight group-data-[collapsible=icon]:hidden\">\n              Acme\n            </span>\n            <Badge\n              variant=\"secondary\"\n              className=\"ml-auto px-1.5 py-0 text-[10px] font-medium group-data-[collapsible=icon]:hidden\"\n            >\n              Pro\n            </Badge>\n          </div>\n        </SidebarHeader>\n\n        <SidebarContent>\n          <SidebarGroup>\n            <SidebarGroupLabel>Menu</SidebarGroupLabel>\n            <SidebarGroupContent>\n              <SidebarMenu>\n                {navItems.map((item) => (\n                  <SidebarMenuItem key={item.label}>\n                    <SidebarMenuButton\n                      isActive={item.active}\n                      tooltip={item.label}\n                      render={<a href=\"#\" />}\n                    >\n                      <item.icon aria-hidden=\"true\" />\n                      <span>{item.label}</span>\n                    </SidebarMenuButton>\n                  </SidebarMenuItem>\n                ))}\n              </SidebarMenu>\n            </SidebarGroupContent>\n          </SidebarGroup>\n\n          <SidebarGroup>\n            <SidebarGroupLabel>Workspace</SidebarGroupLabel>\n            <SidebarGroupContent>\n              <SidebarMenu>\n                {workspaces.map((ws) => (\n                  <SidebarMenuItem key={ws.label}>\n                    <SidebarMenuButton\n                      tooltip={ws.label}\n                      render={<a href=\"#\" />}\n                    >\n                      <ws.icon aria-hidden=\"true\" />\n                      <span>{ws.label}</span>\n                    </SidebarMenuButton>\n                  </SidebarMenuItem>\n                ))}\n              </SidebarMenu>\n            </SidebarGroupContent>\n          </SidebarGroup>\n        </SidebarContent>\n\n        <SidebarFooter>\n          <div className=\"flex items-center gap-2.5 p-1\">\n            <Avatar className=\"size-7\">\n              <AvatarImage\n                src={currentUser.avatar}\n                alt={currentUser.name}\n                className=\"grayscale\"\n              />\n              <AvatarFallback>{currentUser.initials}</AvatarFallback>\n            </Avatar>\n            <div className=\"min-w-0 flex-1 group-data-[collapsible=icon]:hidden\">\n              <p className=\"truncate text-xs leading-none font-semibold\">\n                {currentUser.name}\n              </p>\n              <p className=\"mt-0.5 truncate text-[10px] text-muted-foreground\">\n                {currentUser.email}\n              </p>\n            </div>\n            <UserMenu\n              trigger={\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  className=\"size-6 shrink-0 group-data-[collapsible=icon]:hidden\"\n                  aria-label=\"More options\"\n                >\n                  <RiMoreLine className=\"size-3.5\" aria-hidden=\"true\" />\n                </Button>\n              }\n            />\n          </div>\n        </SidebarFooter>\n      </Sidebar>\n\n      <SidebarInset>\n        <header className=\"flex h-14 items-center gap-4 border-b border-border px-4 sm:px-6\">\n          <SidebarTrigger className=\"-ml-1\" />\n          <div className=\"flex items-center gap-2\">\n            <span className=\"text-xs text-muted-foreground\">Acme</span>\n            <span className=\"text-xs text-muted-foreground\">/</span>\n            <span className=\"text-xs font-semibold\">Dashboard</span>\n          </div>\n          <div className=\"ml-auto flex items-center gap-2\">\n            <button\n              type=\"button\"\n              onClick={() => setCommandOpen(true)}\n              className=\"hidden h-8 w-56 items-center gap-2 border border-border bg-background px-3 text-xs text-muted-foreground transition-colors hover:bg-muted/50 focus-visible:ring-1 focus-visible:ring-ring/50 focus-visible:outline-none sm:inline-flex\"\n            >\n              <RiSearchLine className=\"size-4 shrink-0\" aria-hidden=\"true\" />\n              <span className=\"flex-1 text-left\">Search…</span>\n              <KbdGroup>\n                <Kbd>Ctrl</Kbd>\n                <Kbd>K</Kbd>\n              </KbdGroup>\n            </button>\n            <NotificationsMenu />\n            <UserMenu\n              align=\"end\"\n              trigger={\n                <button\n                  type=\"button\"\n                  className=\"cursor-pointer rounded-none outline-none focus-visible:ring-1 focus-visible:ring-ring/50\"\n                  aria-label=\"Account menu\"\n                >\n                  <Avatar className=\"size-8 ring-1 ring-border ring-offset-1 ring-offset-background transition-opacity hover:opacity-80\">\n                    <AvatarImage\n                      src={currentUser.avatar}\n                      alt={currentUser.name}\n                      className=\"grayscale\"\n                    />\n                    <AvatarFallback>{currentUser.initials}</AvatarFallback>\n                  </Avatar>\n                </button>\n              }\n            />\n          </div>\n        </header>\n\n        <div className=\"flex-1 p-4 sm:p-6\">\n          <div className=\"flex items-start justify-between gap-4\">\n            <div>\n              <h2 className=\"text-xl font-bold tracking-tight\">\n                Welcome back, Alex\n              </h2>\n              <p className=\"mt-1 text-sm text-muted-foreground\">\n                Here&apos;s what&apos;s happening across your workspace today.\n              </p>\n            </div>\n            <Button\n              variant=\"outline\"\n              size=\"sm\"\n              className=\"hidden shrink-0 sm:flex\"\n            >\n              Export Report\n            </Button>\n          </div>\n\n          <div className=\"mt-6 grid gap-3 sm:grid-cols-3\">\n            {stats.map((card) => (\n              <div\n                key={card.label}\n                className=\"border border-border bg-card p-4 transition-shadow hover:shadow-sm\"\n              >\n                <div className=\"flex items-center justify-between gap-2\">\n                  <p className=\"text-xs font-medium text-muted-foreground\">\n                    {card.label}\n                  </p>\n                  <span\n                    className={`flex items-center gap-0.5 text-xs font-semibold tabular-nums ${\n                      card.positive\n                        ? \"text-foreground\"\n                        : \"text-muted-foreground\"\n                    }`}\n                  >\n                    {card.positive ? (\n                      <RiArrowUpLine className=\"size-3\" aria-hidden=\"true\" />\n                    ) : (\n                      <RiArrowDownLine className=\"size-3\" aria-hidden=\"true\" />\n                    )}\n                    {card.delta}\n                  </span>\n                </div>\n                <p className=\"mt-2.5 text-2xl font-bold tracking-tight tabular-nums\">\n                  {card.value}\n                </p>\n                <p className=\"mt-1 text-[11px] text-muted-foreground\">\n                  Vs. Last Month\n                </p>\n              </div>\n            ))}\n          </div>\n\n          <div className=\"mt-6 grid gap-4 lg:grid-cols-5\">\n            <div className=\"border border-border bg-card lg:col-span-3\">\n              <div className=\"flex items-center justify-between border-b border-border px-4 py-3\">\n                <p className=\"text-sm font-semibold\">Recent activity</p>\n                <Button\n                  nativeButton={false}\n                  variant=\"ghost\"\n                  className=\"h-auto px-0 py-0 text-xs text-muted-foreground hover:text-foreground\"\n                  render={<a href=\"#\" />}\n                >\n                  View All\n                </Button>\n              </div>\n              <ul className=\"divide-y divide-border\">\n                {activity.map((item) => (\n                  <li\n                    key={item.id}\n                    className=\"flex items-start gap-3 px-4 py-3 transition-colors hover:bg-muted/40\"\n                  >\n                    <Avatar className=\"mt-0.5 size-7 shrink-0\">\n                      <AvatarImage\n                        src={item.avatar}\n                        alt={item.user}\n                        className=\"grayscale\"\n                      />\n                      <AvatarFallback className=\"text-[10px]\">\n                        {item.initials}\n                      </AvatarFallback>\n                    </Avatar>\n                    <div className=\"min-w-0 flex-1\">\n                      <p className=\"text-xs\">\n                        <span className=\"font-semibold\">{item.user}</span>\n                        <span className=\"text-muted-foreground\">\n                          {\" \"}\n                          {item.action}{\" \"}\n                        </span>\n                        <span className=\"font-medium\">{item.target}</span>\n                      </p>\n                      <p className=\"mt-0.5 text-[11px] text-muted-foreground\">\n                        {item.time}\n                      </p>\n                    </div>\n                    <item.icon\n                      className=\"mt-0.5 size-4 shrink-0 text-muted-foreground\"\n                      aria-hidden=\"true\"\n                    />\n                  </li>\n                ))}\n              </ul>\n            </div>\n\n            <div className=\"border border-border bg-card lg:col-span-2\">\n              <div className=\"flex items-center justify-between border-b border-border px-4 py-3\">\n                <p className=\"text-sm font-semibold\">Active projects</p>\n                <Button\n                  nativeButton={false}\n                  variant=\"ghost\"\n                  className=\"h-auto px-0 py-0 text-xs text-muted-foreground hover:text-foreground\"\n                  render={<a href=\"#\" />}\n                >\n                  View All\n                </Button>\n              </div>\n              <ul className=\"divide-y divide-border\">\n                {projects.map((project) => {\n                  const atRisk = project.status !== \"On Track\"\n                  return (\n                    <li\n                      key={project.name}\n                      className=\"px-4 py-3.5 transition-colors hover:bg-muted/40\"\n                    >\n                      <Progress value={project.progress} className=\"gap-2\">\n                        <div className=\"flex w-full items-center justify-between gap-2\">\n                          <ProgressLabel className=\"truncate text-xs font-semibold text-foreground\">\n                            {project.name}\n                          </ProgressLabel>\n                          {atRisk ? (\n                            <Badge\n                              variant=\"outline\"\n                              className=\"shrink-0 text-[10px] text-muted-foreground\"\n                            >\n                              {project.status}\n                            </Badge>\n                          ) : (\n                            <Badge\n                              variant=\"secondary\"\n                              className=\"shrink-0 text-[10px]\"\n                            >\n                              {project.status}\n                            </Badge>\n                          )}\n                          <ProgressValue className=\"ml-0 w-8 shrink-0 text-right text-[11px]\" />\n                        </div>\n                      </Progress>\n                    </li>\n                  )\n                })}\n              </ul>\n            </div>\n          </div>\n        </div>\n      </SidebarInset>\n\n      <CommandDialog open={commandOpen} onOpenChange={setCommandOpen}>\n        <Command>\n          <CommandInput\n            aria-label=\"Type a command or search\"\n            placeholder=\"Type a command or search…\"\n          />\n          <CommandList>\n            <CommandEmpty>No results found.</CommandEmpty>\n            <CommandGroup heading=\"Navigation\">\n              {navCommands.map((command) => (\n                <CommandItem\n                  key={command.label}\n                  onSelect={() => setCommandOpen(false)}\n                >\n                  <command.icon />\n                  <span>{command.label}</span>\n                </CommandItem>\n              ))}\n            </CommandGroup>\n            <CommandGroup heading=\"Actions\">\n              {actionCommands.map((command) => (\n                <CommandItem\n                  key={command.label}\n                  onSelect={() => setCommandOpen(false)}\n                >\n                  <command.icon />\n                  <span>{command.label}</span>\n                </CommandItem>\n              ))}\n            </CommandGroup>\n          </CommandList>\n        </Command>\n      </CommandDialog>\n    </SidebarProvider>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "meta": {
    "height": "90vh",
    "tier": "free"
  },
  "categories": [
    "app-shell"
  ],
  "type": "registry:block"
}