mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-07-07 14:08:47 +00:00
Introduces a new sidebar-16 block with an inset sidebar and site header navigation. Includes components for main navigation, projects, secondary navigation, and user menu. Updates registry and scripts to include the new sidebar block. Addresses: #5629  
70 lines
18 KiB
JSON
70 lines
18 KiB
JSON
{
|
|
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
"name": "sidebar-16",
|
|
"type": "registry:block",
|
|
"author": "shadcn (https://ui.shadcn.com)",
|
|
"description": "A sidebar with a sticky site header.",
|
|
"registryDependencies": [
|
|
"sidebar",
|
|
"breadcrumb",
|
|
"separator",
|
|
"collapsible",
|
|
"dropdown-menu",
|
|
"avatar",
|
|
"button"
|
|
],
|
|
"files": [
|
|
{
|
|
"path": "blocks/sidebar-16/page.tsx",
|
|
"content": "import { AppSidebar } from \"@/registry/default/blocks/sidebar-16/components/app-sidebar\"\nimport { SiteHeader } from \"@/registry/default/blocks/sidebar-16/components/site-header\"\nimport { SidebarInset, SidebarProvider } from \"@/registry/default/ui/sidebar\"\n\nexport default function Page() {\n return (\n <div className=\"[--header-height:calc(theme(spacing.14))]\">\n <SidebarProvider className=\"flex flex-col\">\n <SiteHeader />\n <div className=\"flex flex-1\">\n <AppSidebar />\n <SidebarInset>\n <div className=\"flex flex-1 flex-col gap-4 p-4\">\n <div className=\"grid auto-rows-min gap-4 md:grid-cols-3\">\n <div className=\"aspect-video rounded-xl bg-muted/50\" />\n <div className=\"aspect-video rounded-xl bg-muted/50\" />\n <div className=\"aspect-video rounded-xl bg-muted/50\" />\n </div>\n <div className=\"min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min\" />\n </div>\n </SidebarInset>\n </div>\n </SidebarProvider>\n </div>\n )\n}\n",
|
|
"type": "registry:page",
|
|
"target": "app/dashboard/page.tsx"
|
|
},
|
|
{
|
|
"path": "blocks/sidebar-16/components/app-sidebar.tsx",
|
|
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport {\n BookOpen,\n Bot,\n Command,\n Frame,\n LifeBuoy,\n Map,\n PieChart,\n Send,\n Settings2,\n SquareTerminal,\n} from \"lucide-react\"\n\nimport { NavMain } from \"@/registry/default/blocks/sidebar-16/components/nav-main\"\nimport { NavProjects } from \"@/registry/default/blocks/sidebar-16/components/nav-projects\"\nimport { NavSecondary } from \"@/registry/default/blocks/sidebar-16/components/nav-secondary\"\nimport { NavUser } from \"@/registry/default/blocks/sidebar-16/components/nav-user\"\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n} from \"@/registry/default/ui/sidebar\"\n\nconst data = {\n user: {\n name: \"shadcn\",\n email: \"m@example.com\",\n avatar: \"/avatars/shadcn.jpg\",\n },\n navMain: [\n {\n title: \"Playground\",\n url: \"#\",\n icon: SquareTerminal,\n isActive: true,\n items: [\n {\n title: \"History\",\n url: \"#\",\n },\n {\n title: \"Starred\",\n url: \"#\",\n },\n {\n title: \"Settings\",\n url: \"#\",\n },\n ],\n },\n {\n title: \"Models\",\n url: \"#\",\n icon: Bot,\n items: [\n {\n title: \"Genesis\",\n url: \"#\",\n },\n {\n title: \"Explorer\",\n url: \"#\",\n },\n {\n title: \"Quantum\",\n url: \"#\",\n },\n ],\n },\n {\n title: \"Documentation\",\n url: \"#\",\n icon: BookOpen,\n items: [\n {\n title: \"Introduction\",\n url: \"#\",\n },\n {\n title: \"Get Started\",\n url: \"#\",\n },\n {\n title: \"Tutorials\",\n url: \"#\",\n },\n {\n title: \"Changelog\",\n url: \"#\",\n },\n ],\n },\n {\n title: \"Settings\",\n url: \"#\",\n icon: Settings2,\n items: [\n {\n title: \"General\",\n url: \"#\",\n },\n {\n title: \"Team\",\n url: \"#\",\n },\n {\n title: \"Billing\",\n url: \"#\",\n },\n {\n title: \"Limits\",\n url: \"#\",\n },\n ],\n },\n ],\n navSecondary: [\n {\n title: \"Support\",\n url: \"#\",\n icon: LifeBuoy,\n },\n {\n title: \"Feedback\",\n url: \"#\",\n icon: Send,\n },\n ],\n projects: [\n {\n name: \"Design Engineering\",\n url: \"#\",\n icon: Frame,\n },\n {\n name: \"Sales & Marketing\",\n url: \"#\",\n icon: PieChart,\n },\n {\n name: \"Travel\",\n url: \"#\",\n icon: Map,\n },\n ],\n}\n\nexport function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {\n return (\n <Sidebar\n className=\"top-[--header-height] !h-[calc(100svh-var(--header-height))]\"\n {...props}\n >\n <SidebarHeader>\n <SidebarMenu>\n <SidebarMenuItem>\n <SidebarMenuButton size=\"lg\" asChild>\n <a href=\"#\">\n <div className=\"flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground\">\n <Command className=\"size-4\" />\n </div>\n <div className=\"grid flex-1 text-left text-sm leading-tight\">\n <span className=\"truncate font-semibold\">Acme Inc</span>\n <span className=\"truncate text-xs\">Enterprise</span>\n </div>\n </a>\n </SidebarMenuButton>\n </SidebarMenuItem>\n </SidebarMenu>\n </SidebarHeader>\n <SidebarContent>\n <NavMain items={data.navMain} />\n <NavProjects projects={data.projects} />\n <NavSecondary items={data.navSecondary} className=\"mt-auto\" />\n </SidebarContent>\n <SidebarFooter>\n <NavUser user={data.user} />\n </SidebarFooter>\n </Sidebar>\n )\n}\n",
|
|
"type": "registry:component",
|
|
"target": ""
|
|
},
|
|
{
|
|
"path": "blocks/sidebar-16/components/nav-main.tsx",
|
|
"content": "\"use client\"\n\nimport { ChevronRight, type LucideIcon } from \"lucide-react\"\n\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"@/registry/default/ui/collapsible\"\nimport {\n SidebarGroup,\n SidebarGroupLabel,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n} from \"@/registry/default/ui/sidebar\"\n\nexport function NavMain({\n items,\n}: {\n items: {\n title: string\n url: string\n icon: LucideIcon\n isActive?: boolean\n items?: {\n title: string\n url: string\n }[]\n }[]\n}) {\n return (\n <SidebarGroup>\n <SidebarGroupLabel>Platform</SidebarGroupLabel>\n <SidebarMenu>\n {items.map((item) => (\n <Collapsible key={item.title} asChild defaultOpen={item.isActive}>\n <SidebarMenuItem>\n <SidebarMenuButton asChild tooltip={item.title}>\n <a href={item.url}>\n <item.icon />\n <span>{item.title}</span>\n </a>\n </SidebarMenuButton>\n {item.items?.length ? (\n <>\n <CollapsibleTrigger asChild>\n <SidebarMenuAction className=\"data-[state=open]:rotate-90\">\n <ChevronRight />\n <span className=\"sr-only\">Toggle</span>\n </SidebarMenuAction>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.items?.map((subItem) => (\n <SidebarMenuSubItem key={subItem.title}>\n <SidebarMenuSubButton asChild>\n <a href={subItem.url}>\n <span>{subItem.title}</span>\n </a>\n </SidebarMenuSubButton>\n </SidebarMenuSubItem>\n ))}\n </SidebarMenuSub>\n </CollapsibleContent>\n </>\n ) : null}\n </SidebarMenuItem>\n </Collapsible>\n ))}\n </SidebarMenu>\n </SidebarGroup>\n )\n}\n",
|
|
"type": "registry:component",
|
|
"target": ""
|
|
},
|
|
{
|
|
"path": "blocks/sidebar-16/components/nav-projects.tsx",
|
|
"content": "\"use client\"\n\nimport {\n Folder,\n MoreHorizontal,\n Share,\n Trash2,\n type LucideIcon,\n} from \"lucide-react\"\n\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/registry/default/ui/dropdown-menu\"\nimport {\n SidebarGroup,\n SidebarGroupLabel,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuButton,\n SidebarMenuItem,\n useSidebar,\n} from \"@/registry/default/ui/sidebar\"\n\nexport function NavProjects({\n projects,\n}: {\n projects: {\n name: string\n url: string\n icon: LucideIcon\n }[]\n}) {\n const { isMobile } = useSidebar()\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 <a href={item.url}>\n <item.icon />\n <span>{item.name}</span>\n </a>\n </SidebarMenuButton>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <SidebarMenuAction showOnHover>\n <MoreHorizontal />\n <span className=\"sr-only\">More</span>\n </SidebarMenuAction>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n className=\"w-48\"\n side={isMobile ? \"bottom\" : \"right\"}\n align={isMobile ? \"end\" : \"start\"}\n >\n <DropdownMenuItem>\n <Folder className=\"text-muted-foreground\" />\n <span>View Project</span>\n </DropdownMenuItem>\n <DropdownMenuItem>\n <Share className=\"text-muted-foreground\" />\n <span>Share Project</span>\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem>\n <Trash2 className=\"text-muted-foreground\" />\n <span>Delete Project</span>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </SidebarMenuItem>\n ))}\n <SidebarMenuItem>\n <SidebarMenuButton>\n <MoreHorizontal />\n <span>More</span>\n </SidebarMenuButton>\n </SidebarMenuItem>\n </SidebarMenu>\n </SidebarGroup>\n )\n}\n",
|
|
"type": "registry:component",
|
|
"target": ""
|
|
},
|
|
{
|
|
"path": "blocks/sidebar-16/components/nav-secondary.tsx",
|
|
"content": "import * as React from \"react\"\nimport { type LucideIcon } from \"lucide-react\"\n\nimport {\n SidebarGroup,\n SidebarGroupContent,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n} from \"@/registry/default/ui/sidebar\"\n\nexport function NavSecondary({\n items,\n ...props\n}: {\n items: {\n title: string\n url: string\n icon: LucideIcon\n }[]\n} & React.ComponentPropsWithoutRef<typeof SidebarGroup>) {\n return (\n <SidebarGroup {...props}>\n <SidebarGroupContent>\n <SidebarMenu>\n {items.map((item) => (\n <SidebarMenuItem key={item.title}>\n <SidebarMenuButton asChild size=\"sm\">\n <a href={item.url}>\n <item.icon />\n <span>{item.title}</span>\n </a>\n </SidebarMenuButton>\n </SidebarMenuItem>\n ))}\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n )\n}\n",
|
|
"type": "registry:component",
|
|
"target": ""
|
|
},
|
|
{
|
|
"path": "blocks/sidebar-16/components/nav-user.tsx",
|
|
"content": "\"use client\"\n\nimport {\n BadgeCheck,\n Bell,\n ChevronsUpDown,\n CreditCard,\n LogOut,\n Sparkles,\n} from \"lucide-react\"\n\nimport {\n Avatar,\n AvatarFallback,\n AvatarImage,\n} from \"@/registry/default/ui/avatar\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/registry/default/ui/dropdown-menu\"\nimport {\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n useSidebar,\n} from \"@/registry/default/ui/sidebar\"\n\nexport function NavUser({\n user,\n}: {\n user: {\n name: string\n email: string\n avatar: string\n }\n}) {\n const { isMobile } = useSidebar()\n\n return (\n <SidebarMenu>\n <SidebarMenuItem>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <SidebarMenuButton\n size=\"lg\"\n className=\"data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground\"\n >\n <Avatar className=\"h-8 w-8 rounded-lg\">\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-semibold\">{user.name}</span>\n <span className=\"truncate text-xs\">{user.email}</span>\n </div>\n <ChevronsUpDown className=\"ml-auto size-4\" />\n </SidebarMenuButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n className=\"w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg\"\n side={isMobile ? \"bottom\" : \"right\"}\n align=\"end\"\n sideOffset={4}\n >\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 className=\"h-8 w-8 rounded-lg\">\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-semibold\">{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 </SidebarMenuItem>\n </SidebarMenu>\n )\n}\n",
|
|
"type": "registry:component",
|
|
"target": ""
|
|
},
|
|
{
|
|
"path": "blocks/sidebar-16/components/search-form.tsx",
|
|
"content": "import { Search } from \"lucide-react\"\n\nimport { Label } from \"@/registry/default/ui/label\"\nimport { SidebarInput } from \"@/registry/default/ui/sidebar\"\n\nexport function SearchForm({ ...props }: React.ComponentProps<\"form\">) {\n return (\n <form {...props}>\n <div className=\"relative\">\n <Label htmlFor=\"search\" className=\"sr-only\">\n Search\n </Label>\n <SidebarInput\n id=\"search\"\n placeholder=\"Type to search...\"\n className=\"h-8 pl-7\"\n />\n <Search className=\"pointer-events-none absolute left-2 top-1/2 size-4 -translate-y-1/2 select-none opacity-50\" />\n </div>\n </form>\n )\n}\n",
|
|
"type": "registry:component",
|
|
"target": ""
|
|
},
|
|
{
|
|
"path": "blocks/sidebar-16/components/site-header.tsx",
|
|
"content": "\"use client\"\n\nimport { SidebarIcon } from \"lucide-react\"\n\nimport { SearchForm } from \"@/registry/default/blocks/sidebar-16/components/search-form\"\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/registry/default/ui/breadcrumb\"\nimport { Button } from \"@/registry/default/ui/button\"\nimport { Separator } from \"@/registry/default/ui/separator\"\nimport { useSidebar } from \"@/registry/default/ui/sidebar\"\n\nexport function SiteHeader() {\n const { toggleSidebar } = useSidebar()\n\n return (\n <header className=\"fle sticky top-0 z-50 w-full items-center border-b bg-background\">\n <div className=\"flex h-[--header-height] w-full items-center gap-2 px-4\">\n <Button\n className=\"h-8 w-8\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={toggleSidebar}\n >\n <SidebarIcon />\n </Button>\n <Separator orientation=\"vertical\" className=\"mr-2 h-4\" />\n <Breadcrumb className=\"hidden sm:block\">\n <BreadcrumbList>\n <BreadcrumbItem>\n <BreadcrumbLink href=\"#\">\n Building Your Application\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbPage>Data Fetching</BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n <SearchForm className=\"w-full sm:ml-auto sm:w-auto\" />\n </div>\n </header>\n )\n}\n",
|
|
"type": "registry:component",
|
|
"target": ""
|
|
}
|
|
],
|
|
"categories": [
|
|
"sidebar",
|
|
"dashboard"
|
|
]
|
|
} |