feat: add docs for sidebar

This commit is contained in:
shadcn
2026-01-20 11:35:07 +04:00
parent a7bd5d2d22
commit 528b27a63f
34 changed files with 2839 additions and 88 deletions

View File

@@ -4,7 +4,11 @@ import { type Metadata } from "next"
import { notFound } from "next/navigation"
import { siteConfig } from "@/lib/config"
import { getRegistryComponent, getRegistryItem } from "@/lib/registry"
import {
getDemoItem,
getRegistryComponent,
getRegistryItem,
} from "@/lib/registry"
import { absoluteUrl } from "@/lib/utils"
import { getStyle, legacyStyles, type Style } from "@/registry/_legacy-styles"
@@ -18,7 +22,12 @@ export const dynamicParams = false
const getCachedRegistryItem = React.cache(
async (name: string, styleName: Style["name"]) => {
return await getRegistryItem(name, styleName)
// Try registry item first, then fallback to demo item (for examples).
const item = await getRegistryItem(name, styleName)
if (item) {
return item
}
return await getDemoItem(name, styleName)
}
)
@@ -75,9 +84,52 @@ export async function generateMetadata({
export async function generateStaticParams() {
const { Index } = await import("@/registry/__index__")
const { Index: BasesIndex } = await import("@/registry/bases/__index__")
const { ExamplesIndex } = await import("@/examples/__index__")
const params: Array<{ style: string; name: string }> = []
for (const style of legacyStyles) {
// Check if this is a base-prefixed style (e.g., base-nova, radix-nova).
const baseMatch = style.name.match(/^(base|radix)-/)
if (baseMatch) {
const baseName = baseMatch[1]
// Add examples from ExamplesIndex.
const examples = ExamplesIndex[baseName]
if (examples) {
for (const exampleName of Object.keys(examples)) {
params.push({
style: style.name,
name: exampleName,
})
}
}
// Add UI components from BasesIndex.
const baseIndex = BasesIndex[baseName]
if (baseIndex) {
for (const itemName in baseIndex) {
const item = baseIndex[itemName]
if (
[
"registry:block",
"registry:component",
"registry:example",
"registry:internal",
].includes(item.type)
) {
params.push({
style: style.name,
name: item.name,
})
}
}
}
continue
}
// Handle legacy styles (e.g., new-york-v4).
if (!Index[style.name]) {
continue
}

View File

@@ -29,14 +29,14 @@ export function ComponentPreview({
return (
<div className="relative aspect-[4/2.5] w-full overflow-hidden rounded-xl border md:-mx-1">
<Image
src={`/r/styles/new-york-v4/${name}-light.png`}
src={`/r/styles/${styleName}/${name}-light.png`}
alt={name}
width={1440}
height={900}
className="bg-background absolute top-0 left-0 z-20 w-[970px] max-w-none sm:w-[1280px] md:hidden dark:hidden md:dark:hidden"
/>
<Image
src={`/r/styles/new-york-v4/${name}-dark.png`}
src={`/r/styles/${styleName}/${name}-dark.png`}
alt={name}
width={1440}
height={900}
@@ -63,8 +63,6 @@ export function ComponentPreview({
)
}
return (
<ComponentPreviewTabs
className={className}

View File

@@ -6,11 +6,7 @@ component: true
---
<figure className="flex flex-col gap-4">
<ComponentPreview
styleName="base-nova"
name="sidebar-07"
type="block"
/>
<ComponentPreview styleName="base-nova" name="sidebar-demo" type="block" />
<figcaption className="text-center text-sm text-gray-500">
A sidebar that collapses to icons.
</figcaption>
@@ -318,15 +314,8 @@ export function AppSidebar() {
You should see something like this:
<figure className="flex flex-col gap-4">
<ComponentPreview
styleName="base-nova"
name="sidebar-demo"
title="Sidebar"
type="block"
description="Your first sidebar."
className="w-full"
/>
<figure className="mt-6 flex flex-col gap-4">
<ComponentPreview styleName="base-nova" name="sidebar-demo" type="block" />
<figcaption className="text-center text-sm text-gray-500">
Your first sidebar.
</figcaption>
@@ -545,14 +534,7 @@ Use the `SidebarHeader` component to add a sticky header to the sidebar.
The following example adds a `<DropdownMenu>` to the `SidebarHeader`.
<figure className="mt-6 flex flex-col gap-4">
<ComponentPreview
styleName="base-nova"
name="sidebar-header"
title="Sidebar"
type="block"
description="A sidebar header with a dropdown menu."
className="w-full"
/>
<ComponentPreview styleName="base-nova" name="sidebar-header" type="block" />
<figcaption className="text-center text-sm text-gray-500">
A sidebar header with a dropdown menu.
</figcaption>
@@ -592,14 +574,7 @@ Use the `SidebarFooter` component to add a sticky footer to the sidebar.
The following example adds a `<DropdownMenu>` to the `SidebarFooter`.
<figure className="mt-6 flex flex-col gap-4">
<ComponentPreview
styleName="base-nova"
name="sidebar-footer"
title="Sidebar"
type="block"
description="A sidebar footer with a dropdown menu."
className="w-full"
/>
<ComponentPreview styleName="base-nova" name="sidebar-footer" type="block" />
<figcaption className="text-center text-sm text-gray-500">
A sidebar footer with a dropdown menu.
</figcaption>
@@ -672,14 +647,7 @@ Use the `SidebarGroup` component to create a section within the sidebar.
A `SidebarGroup` has a `SidebarGroupLabel`, a `SidebarGroupContent` and an optional `SidebarGroupAction`.
<figure className="mt-6 flex flex-col gap-4">
<ComponentPreview
styleName="base-nova"
name="sidebar-group"
title="Sidebar Group"
type="block"
description="A sidebar group."
className="w-full"
/>
<ComponentPreview styleName="base-nova" name="sidebar-group" type="block" />
<figcaption className="text-center text-sm text-gray-500">
A sidebar group.
</figcaption>
@@ -713,10 +681,7 @@ To make a `SidebarGroup` collapsible, wrap it in a `Collapsible`.
<ComponentPreview
styleName="base-nova"
name="sidebar-group-collapsible"
title="Sidebar Group"
type="block"
description="A collapsible sidebar group."
className="w-full"
/>
<figcaption className="text-center text-sm text-gray-500">
A collapsible sidebar group.
@@ -756,10 +721,7 @@ Use the `SidebarGroupAction` component to add an action button to the `SidebarGr
<ComponentPreview
styleName="base-nova"
name="sidebar-group-action"
title="Sidebar Group"
type="block"
description="A sidebar group with an action button."
className="w-full"
/>
<figcaption className="text-center text-sm text-gray-500">
A sidebar group with an action button.
@@ -804,14 +766,7 @@ A `SidebarMenu` component is composed of `SidebarMenuItem`, `SidebarMenuButton`,
Here's an example of a `SidebarMenu` component rendering a list of projects.
<figure className="mt-6 flex flex-col gap-4">
<ComponentPreview
styleName="base-nova"
name="sidebar-menu"
title="Sidebar Menu"
type="block"
description="A sidebar menu with a list of projects."
className="w-full"
/>
<ComponentPreview styleName="base-nova" name="sidebar-menu" type="block" />
<figcaption className="text-center text-sm text-gray-500">
A sidebar menu with a list of projects.
</figcaption>
@@ -906,10 +861,7 @@ Here's an example of a `SidebarMenuAction` component rendering a `DropdownMenu`.
<ComponentPreview
styleName="base-nova"
name="sidebar-menu-action"
title="Sidebar Menu Action"
type="block"
description="A sidebar menu action with a dropdown menu."
className="w-full"
/>
<figcaption className="text-center text-sm text-gray-500">
A sidebar menu action with a dropdown menu.
@@ -952,10 +904,7 @@ Use `<SidebarMenuSubItem />` and `<SidebarMenuSubButton />` to render a submenu
<ComponentPreview
styleName="base-nova"
name="sidebar-menu-sub"
title="Sidebar Menu Sub"
type="block"
description="A sidebar menu sub."
className="w-full"
/>
<figcaption className="text-center text-sm text-gray-500">
A sidebar menu with a submenu.
@@ -984,10 +933,7 @@ To make a `SidebarMenu` component collapsible, wrap it and the `SidebarMenuSub`
<ComponentPreview
styleName="base-nova"
name="sidebar-menu-collapsible"
title="Sidebar Menu"
type="block"
description="A collapsible sidebar menu."
className="w-full"
/>
<figcaption className="text-center text-sm text-gray-500">
A collapsible sidebar menu.
@@ -1019,10 +965,7 @@ The `SidebarMenuBadge` component is used to render a badge within a `SidebarMenu
<ComponentPreview
styleName="base-nova"
name="sidebar-menu-badge"
title="Sidebar Menu Badge"
type="block"
description="A sidebar menu badge."
className="w-full"
/>
<figcaption className="text-center text-sm text-gray-500">
A sidebar menu with a badge.
@@ -1121,14 +1064,7 @@ The `SidebarRail` component is used to render a rail within a `Sidebar`. This ra
Here's an example of a `SidebarMenu` component rendering a list of projects using React Server Components.
<figure className="mt-6 flex flex-col gap-4">
<ComponentPreview
styleName="base-nova"
name="sidebar-rsc"
title="Sidebar Menu RSC"
type="block"
description="A sidebar menu using React Server Components."
className="w-full"
/>
<ComponentPreview styleName="base-nova" name="sidebar-rsc" type="block" />
<figcaption className="text-center text-sm text-gray-500">
A sidebar menu using React Server Components.
</figcaption>
@@ -1274,10 +1210,7 @@ Use the `open` and `onOpenChange` props to control the sidebar.
<ComponentPreview
styleName="base-nova"
name="sidebar-controlled"
title="Sidebar Controlled"
type="block"
description="A controlled sidebar."
className="w-full"
/>
<figcaption className="text-center text-sm text-gray-500">
A controlled sidebar.

View File

@@ -321,7 +321,7 @@ export function AppSidebar() {
You should see something like this:
<figure className="flex flex-col gap-4">
<figure className="mt-6 flex flex-col gap-4">
<ComponentPreview
styleName="radix-nova"
name="sidebar-demo"

View File

@@ -3827,6 +3827,175 @@ export const ExamplesIndex: Record<string, Record<string, any>> = {
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-controlled": {
name: "sidebar-controlled",
filePath: "examples/radix/sidebar-controlled.tsx",
component: React.lazy(async () => {
const mod = await import("./radix/sidebar-controlled")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-controlled"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-demo": {
name: "sidebar-demo",
filePath: "examples/radix/sidebar-demo.tsx",
component: React.lazy(async () => {
const mod = await import("./radix/sidebar-demo")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-demo"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-footer": {
name: "sidebar-footer",
filePath: "examples/radix/sidebar-footer.tsx",
component: React.lazy(async () => {
const mod = await import("./radix/sidebar-footer")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-footer"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-group-action": {
name: "sidebar-group-action",
filePath: "examples/radix/sidebar-group-action.tsx",
component: React.lazy(async () => {
const mod = await import("./radix/sidebar-group-action")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-group-action"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-group-collapsible": {
name: "sidebar-group-collapsible",
filePath: "examples/radix/sidebar-group-collapsible.tsx",
component: React.lazy(async () => {
const mod = await import("./radix/sidebar-group-collapsible")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-group-collapsible"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-group": {
name: "sidebar-group",
filePath: "examples/radix/sidebar-group.tsx",
component: React.lazy(async () => {
const mod = await import("./radix/sidebar-group")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-group"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-header": {
name: "sidebar-header",
filePath: "examples/radix/sidebar-header.tsx",
component: React.lazy(async () => {
const mod = await import("./radix/sidebar-header")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-header"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-menu-action": {
name: "sidebar-menu-action",
filePath: "examples/radix/sidebar-menu-action.tsx",
component: React.lazy(async () => {
const mod = await import("./radix/sidebar-menu-action")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-menu-action"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-menu-badge": {
name: "sidebar-menu-badge",
filePath: "examples/radix/sidebar-menu-badge.tsx",
component: React.lazy(async () => {
const mod = await import("./radix/sidebar-menu-badge")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-menu-badge"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-menu-collapsible": {
name: "sidebar-menu-collapsible",
filePath: "examples/radix/sidebar-menu-collapsible.tsx",
component: React.lazy(async () => {
const mod = await import("./radix/sidebar-menu-collapsible")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-menu-collapsible"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-menu-sub": {
name: "sidebar-menu-sub",
filePath: "examples/radix/sidebar-menu-sub.tsx",
component: React.lazy(async () => {
const mod = await import("./radix/sidebar-menu-sub")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-menu-sub"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-menu": {
name: "sidebar-menu",
filePath: "examples/radix/sidebar-menu.tsx",
component: React.lazy(async () => {
const mod = await import("./radix/sidebar-menu")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-menu"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-rsc": {
name: "sidebar-rsc",
filePath: "examples/radix/sidebar-rsc.tsx",
component: React.lazy(async () => {
const mod = await import("./radix/sidebar-rsc")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-rsc"
return { default: mod.default || mod[exportName] }
}),
},
"skeleton-avatar": {
name: "skeleton-avatar",
filePath: "examples/radix/skeleton-avatar.tsx",
@@ -8548,6 +8717,175 @@ export const ExamplesIndex: Record<string, Record<string, any>> = {
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-controlled": {
name: "sidebar-controlled",
filePath: "examples/base/sidebar-controlled.tsx",
component: React.lazy(async () => {
const mod = await import("./base/sidebar-controlled")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-controlled"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-demo": {
name: "sidebar-demo",
filePath: "examples/base/sidebar-demo.tsx",
component: React.lazy(async () => {
const mod = await import("./base/sidebar-demo")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-demo"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-footer": {
name: "sidebar-footer",
filePath: "examples/base/sidebar-footer.tsx",
component: React.lazy(async () => {
const mod = await import("./base/sidebar-footer")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-footer"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-group-action": {
name: "sidebar-group-action",
filePath: "examples/base/sidebar-group-action.tsx",
component: React.lazy(async () => {
const mod = await import("./base/sidebar-group-action")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-group-action"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-group-collapsible": {
name: "sidebar-group-collapsible",
filePath: "examples/base/sidebar-group-collapsible.tsx",
component: React.lazy(async () => {
const mod = await import("./base/sidebar-group-collapsible")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-group-collapsible"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-group": {
name: "sidebar-group",
filePath: "examples/base/sidebar-group.tsx",
component: React.lazy(async () => {
const mod = await import("./base/sidebar-group")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-group"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-header": {
name: "sidebar-header",
filePath: "examples/base/sidebar-header.tsx",
component: React.lazy(async () => {
const mod = await import("./base/sidebar-header")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-header"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-menu-action": {
name: "sidebar-menu-action",
filePath: "examples/base/sidebar-menu-action.tsx",
component: React.lazy(async () => {
const mod = await import("./base/sidebar-menu-action")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-menu-action"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-menu-badge": {
name: "sidebar-menu-badge",
filePath: "examples/base/sidebar-menu-badge.tsx",
component: React.lazy(async () => {
const mod = await import("./base/sidebar-menu-badge")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-menu-badge"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-menu-collapsible": {
name: "sidebar-menu-collapsible",
filePath: "examples/base/sidebar-menu-collapsible.tsx",
component: React.lazy(async () => {
const mod = await import("./base/sidebar-menu-collapsible")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-menu-collapsible"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-menu-sub": {
name: "sidebar-menu-sub",
filePath: "examples/base/sidebar-menu-sub.tsx",
component: React.lazy(async () => {
const mod = await import("./base/sidebar-menu-sub")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-menu-sub"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-menu": {
name: "sidebar-menu",
filePath: "examples/base/sidebar-menu.tsx",
component: React.lazy(async () => {
const mod = await import("./base/sidebar-menu")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-menu"
return { default: mod.default || mod[exportName] }
}),
},
"sidebar-rsc": {
name: "sidebar-rsc",
filePath: "examples/base/sidebar-rsc.tsx",
component: React.lazy(async () => {
const mod = await import("./base/sidebar-rsc")
const exportName =
Object.keys(mod).find(
(key) =>
typeof mod[key] === "function" || typeof mod[key] === "object"
) || "sidebar-rsc"
return { default: mod.default || mod[exportName] }
}),
},
"skeleton-avatar": {
name: "skeleton-avatar",
filePath: "examples/base/skeleton-avatar.tsx",

View File

@@ -0,0 +1,93 @@
"use client"
import * as React from "react"
import { Button } from "@/examples/base/ui/button"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarInset,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/examples/base/ui/sidebar"
import {
FrameIcon,
LifeBuoyIcon,
MapIcon,
PanelLeftCloseIcon,
PanelLeftOpenIcon,
PieChartIcon,
SendIcon,
} from "lucide-react"
const projects = [
{
name: "Design Engineering",
url: "#",
icon: FrameIcon,
},
{
name: "Sales & Marketing",
url: "#",
icon: PieChartIcon,
},
{
name: "Travel",
url: "#",
icon: MapIcon,
},
{
name: "Support",
url: "#",
icon: LifeBuoyIcon,
},
{
name: "Feedback",
url: "#",
icon: SendIcon,
},
]
export default function AppSidebar() {
const [open, setOpen] = React.useState(true)
return (
<SidebarProvider open={open} onOpenChange={setOpen}>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{projects.map((project) => (
<SidebarMenuItem key={project.name}>
<SidebarMenuButton render={<a href={project.url} />}>
<project.icon />
<span>{project.name}</span>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
<SidebarInset>
<header className="flex h-12 items-center justify-between px-4">
<Button
onClick={() => setOpen((open) => !open)}
size="sm"
variant="ghost"
>
{open ? <PanelLeftCloseIcon /> : <PanelLeftOpenIcon />}
<span>{open ? "Close" : "Open"} Sidebar</span>
</Button>
</header>
</SidebarInset>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,81 @@
"use client"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarInset,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
SidebarTrigger,
} from "@/examples/base/ui/sidebar"
import {
CalendarIcon,
HomeIcon,
InboxIcon,
SearchIcon,
SettingsIcon,
} from "lucide-react"
const items = [
{
title: "Home",
url: "#",
icon: HomeIcon,
},
{
title: "Inbox",
url: "#",
icon: InboxIcon,
},
{
title: "Calendar",
url: "#",
icon: CalendarIcon,
},
{
title: "Search",
url: "#",
icon: SearchIcon,
},
{
title: "Settings",
url: "#",
icon: SettingsIcon,
},
]
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Application</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{items.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton render={<a href={item.url} />}>
<item.icon />
<span>{item.title}</span>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
<SidebarInset>
<header className="flex h-12 items-center justify-between px-4">
<SidebarTrigger />
</header>
</SidebarInset>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,67 @@
"use client"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/examples/base/ui/dropdown-menu"
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarHeader,
SidebarInset,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
SidebarTrigger,
} from "@/examples/base/ui/sidebar"
import { ChevronUpIcon } from "lucide-react"
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarHeader />
<SidebarContent />
<SidebarFooter>
<SidebarMenu>
<SidebarMenuItem>
<DropdownMenu>
<DropdownMenuTrigger
render={
<SidebarMenuButton className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground" />
}
>
Username
<ChevronUpIcon className="ml-auto" />
</DropdownMenuTrigger>
<DropdownMenuContent
side="top"
className="w-(--radix-popper-anchor-width)"
>
<DropdownMenuItem>
<span>Account</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>Billing</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>Sign out</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
</Sidebar>
<SidebarInset>
<header className="flex h-12 items-center justify-between px-4">
<SidebarTrigger />
</header>
</SidebarInset>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,64 @@
"use client"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupAction,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/examples/base/ui/sidebar"
import { FrameIcon, MapIcon, PieChartIcon, PlusIcon } from "lucide-react"
import { toast, Toaster } from "sonner"
export default function AppSidebar() {
return (
<SidebarProvider>
<Toaster
position="bottom-left"
toastOptions={{
className: "ml-[160px]",
}}
/>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupAction
title="Add Project"
onClick={() => toast("You clicked the group action!")}
>
<PlusIcon /> <span className="sr-only">Add Project</span>
</SidebarGroupAction>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton render={<a href="#" />}>
<FrameIcon />
<span>Design Engineering</span>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton render={<a href="#" />}>
<PieChartIcon />
<span>Sales & Marketing</span>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton render={<a href="#" />}>
<MapIcon />
<span>Travel</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,59 @@
"use client"
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/examples/base/ui/collapsible"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/examples/base/ui/sidebar"
import { ChevronDownIcon, LifeBuoyIcon, SendIcon } from "lucide-react"
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<Collapsible defaultOpen className="group/collapsible">
<SidebarGroup>
<SidebarGroupLabel
render={<CollapsibleTrigger />}
className="hover:bg-sidebar-accent hover:text-sidebar-accent-foreground text-sm"
>
Help
<ChevronDownIcon className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-180" />
</SidebarGroupLabel>
<CollapsibleContent>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton>
<LifeBuoyIcon />
Support
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton>
<SendIcon />
Feedback
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</CollapsibleContent>
</SidebarGroup>
</Collapsible>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,44 @@
"use client"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/examples/base/ui/sidebar"
import { LifeBuoyIcon, SendIcon } from "lucide-react"
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Help</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton>
<LifeBuoyIcon />
Support
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton>
<SendIcon />
Feedback
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,57 @@
"use client"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/examples/base/ui/dropdown-menu"
import {
Sidebar,
SidebarHeader,
SidebarInset,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
SidebarTrigger,
} from "@/examples/base/ui/sidebar"
import { ChevronDownIcon } from "lucide-react"
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarHeader>
<SidebarMenu>
<SidebarMenuItem>
<DropdownMenu>
<DropdownMenuTrigger
render={
<SidebarMenuButton className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground" />
}
>
Select Workspace
<ChevronDownIcon className="ml-auto" />
</DropdownMenuTrigger>
<DropdownMenuContent className="w-(--radix-popper-anchor-width)">
<DropdownMenuItem>
<span>Acme Inc</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>Acme Corp.</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
</Sidebar>
<SidebarInset>
<header className="flex h-12 items-center justify-between px-4">
<SidebarTrigger />
</header>
</SidebarInset>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,99 @@
"use client"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/examples/base/ui/dropdown-menu"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuAction,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/examples/base/ui/sidebar"
import {
FrameIcon,
LifeBuoyIcon,
MapIcon,
MoreHorizontalIcon,
PieChartIcon,
SendIcon,
} from "lucide-react"
const projects = [
{
name: "Design Engineering",
url: "#",
icon: FrameIcon,
},
{
name: "Sales & Marketing",
url: "#",
icon: PieChartIcon,
},
{
name: "Travel",
url: "#",
icon: MapIcon,
},
{
name: "Support",
url: "#",
icon: LifeBuoyIcon,
},
{
name: "Feedback",
url: "#",
icon: SendIcon,
},
]
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{projects.map((project) => (
<SidebarMenuItem key={project.name}>
<SidebarMenuButton
render={<a href={project.url} />}
className="group-has-[[data-state=open]]/menu-item:bg-sidebar-accent"
>
<project.icon />
<span>{project.name}</span>
</SidebarMenuButton>
<DropdownMenu>
<DropdownMenuTrigger render={<SidebarMenuAction />}>
<MoreHorizontalIcon />
<span className="sr-only">More</span>
</DropdownMenuTrigger>
<DropdownMenuContent side="right" align="start">
<DropdownMenuItem>
<span>Edit Project</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>Delete Project</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,84 @@
"use client"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuBadge,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/examples/base/ui/sidebar"
import {
FrameIcon,
LifeBuoyIcon,
MapIcon,
PieChartIcon,
SendIcon,
} from "lucide-react"
const projects = [
{
name: "Design Engineering",
url: "#",
icon: FrameIcon,
badge: "24",
},
{
name: "Sales & Marketing",
url: "#",
icon: PieChartIcon,
badge: "12",
},
{
name: "Travel",
url: "#",
icon: MapIcon,
badge: "3",
},
{
name: "Support",
url: "#",
icon: LifeBuoyIcon,
badge: "21",
},
{
name: "Feedback",
url: "#",
icon: SendIcon,
badge: "8",
},
]
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{projects.map((project) => (
<SidebarMenuItem key={project.name}>
<SidebarMenuButton
render={<a href={project.url} />}
className="group-has-[[data-state=open]]/menu-item:bg-sidebar-accent"
>
<project.icon />
<span>{project.name}</span>
</SidebarMenuButton>
<SidebarMenuBadge>{project.badge}</SidebarMenuBadge>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,193 @@
"use client"
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/examples/base/ui/collapsible"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSub,
SidebarMenuSubButton,
SidebarMenuSubItem,
SidebarProvider,
} from "@/examples/base/ui/sidebar"
import { ChevronRightIcon } from "lucide-react"
const items = [
{
title: "Getting Started",
url: "#",
items: [
{
title: "Installation",
url: "#",
},
{
title: "Project Structure",
url: "#",
},
],
},
{
title: "Building Your Application",
url: "#",
items: [
{
title: "Routing",
url: "#",
},
{
title: "Data Fetching",
url: "#",
isActive: true,
},
{
title: "Rendering",
url: "#",
},
{
title: "Caching",
url: "#",
},
{
title: "Styling",
url: "#",
},
{
title: "Optimizing",
url: "#",
},
{
title: "Configuring",
url: "#",
},
{
title: "Testing",
url: "#",
},
{
title: "Authentication",
url: "#",
},
{
title: "Deploying",
url: "#",
},
{
title: "Upgrading",
url: "#",
},
{
title: "Examples",
url: "#",
},
],
},
{
title: "API Reference",
url: "#",
items: [
{
title: "Components",
url: "#",
},
{
title: "File Conventions",
url: "#",
},
{
title: "Functions",
url: "#",
},
{
title: "next.config.js Options",
url: "#",
},
{
title: "CLI",
url: "#",
},
{
title: "Edge Runtime",
url: "#",
},
],
},
{
title: "Architecture",
url: "#",
items: [
{
title: "Accessibility",
url: "#",
},
{
title: "Fast Refresh",
url: "#",
},
{
title: "Next.js Compiler",
url: "#",
},
{
title: "Supported Browsers",
url: "#",
},
{
title: "Turbopack",
url: "#",
},
],
},
]
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupContent>
<SidebarMenu>
{items.map((item, index) => (
<Collapsible
key={index}
className="group/collapsible"
defaultOpen={index === 0}
>
<SidebarMenuItem>
<CollapsibleTrigger render={<SidebarMenuButton />}>
<span>{item.title}</span>
<ChevronRightIcon className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-90" />
</CollapsibleTrigger>
<CollapsibleContent>
<SidebarMenuSub>
{item.items.map((subItem, subIndex) => (
<SidebarMenuSubItem key={subIndex}>
<SidebarMenuSubButton
render={<a href={subItem.url} />}
>
<span>{subItem.title}</span>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
))}
</SidebarMenuSub>
</CollapsibleContent>
</SidebarMenuItem>
</Collapsible>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,178 @@
"use client"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSub,
SidebarMenuSubButton,
SidebarMenuSubItem,
SidebarProvider,
} from "@/examples/base/ui/sidebar"
const items = [
{
title: "Getting Started",
url: "#",
items: [
{
title: "Installation",
url: "#",
},
{
title: "Project Structure",
url: "#",
},
],
},
{
title: "Building Your Application",
url: "#",
items: [
{
title: "Routing",
url: "#",
},
{
title: "Data Fetching",
url: "#",
isActive: true,
},
{
title: "Rendering",
url: "#",
},
{
title: "Caching",
url: "#",
},
{
title: "Styling",
url: "#",
},
{
title: "Optimizing",
url: "#",
},
{
title: "Configuring",
url: "#",
},
{
title: "Testing",
url: "#",
},
{
title: "Authentication",
url: "#",
},
{
title: "Deploying",
url: "#",
},
{
title: "Upgrading",
url: "#",
},
{
title: "Examples",
url: "#",
},
],
},
{
title: "API Reference",
url: "#",
items: [
{
title: "Components",
url: "#",
},
{
title: "File Conventions",
url: "#",
},
{
title: "Functions",
url: "#",
},
{
title: "next.config.js Options",
url: "#",
},
{
title: "CLI",
url: "#",
},
{
title: "Edge Runtime",
url: "#",
},
],
},
{
title: "Architecture",
url: "#",
items: [
{
title: "Accessibility",
url: "#",
},
{
title: "Fast Refresh",
url: "#",
},
{
title: "Next.js Compiler",
url: "#",
},
{
title: "Supported Browsers",
url: "#",
},
{
title: "Turbopack",
url: "#",
},
],
},
]
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupContent>
<SidebarMenu>
{items.map((item, index) => (
<SidebarMenuItem key={index}>
<SidebarMenuButton render={<a href={item.url} />}>
<span>{item.title}</span>
</SidebarMenuButton>
<SidebarMenuSub>
{item.items.map((subItem, subIndex) => (
<SidebarMenuSubItem key={subIndex}>
<SidebarMenuSubButton
render={<a href={subItem.url} />}
>
<span>{subItem.title}</span>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
))}
</SidebarMenuSub>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,74 @@
"use client"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/examples/base/ui/sidebar"
import {
FrameIcon,
LifeBuoyIcon,
MapIcon,
PieChartIcon,
SendIcon,
} from "lucide-react"
const projects = [
{
name: "Design Engineering",
url: "#",
icon: FrameIcon,
},
{
name: "Sales & Marketing",
url: "#",
icon: PieChartIcon,
},
{
name: "Travel",
url: "#",
icon: MapIcon,
},
{
name: "Support",
url: "#",
icon: LifeBuoyIcon,
},
{
name: "Feedback",
url: "#",
icon: SendIcon,
},
]
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{projects.map((project) => (
<SidebarMenuItem key={project.name}>
<SidebarMenuButton render={<a href={project.url} />}>
<project.icon />
<span>{project.name}</span>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,107 @@
import * as React from "react"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSkeleton,
SidebarProvider,
} from "@/examples/base/ui/sidebar"
import {
FrameIcon,
LifeBuoyIcon,
MapIcon,
PieChartIcon,
SendIcon,
} from "lucide-react"
const projects = [
{
name: "Design Engineering",
url: "#",
icon: FrameIcon,
badge: "24",
},
{
name: "Sales & Marketing",
url: "#",
icon: PieChartIcon,
badge: "12",
},
{
name: "Travel",
url: "#",
icon: MapIcon,
badge: "3",
},
{
name: "Support",
url: "#",
icon: LifeBuoyIcon,
badge: "21",
},
{
name: "Feedback",
url: "#",
icon: SendIcon,
badge: "8",
},
]
// Dummy fetch function.
async function fetchProjects() {
await new Promise((resolve) => setTimeout(resolve, 3000))
return projects
}
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupContent>
<React.Suspense fallback={<NavProjectsSkeleton />}>
<NavProjects />
</React.Suspense>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}
function NavProjectsSkeleton() {
return (
<SidebarMenu>
{Array.from({ length: 5 }).map((_, index) => (
<SidebarMenuItem key={index}>
<SidebarMenuSkeleton showIcon />
</SidebarMenuItem>
))}
</SidebarMenu>
)
}
async function NavProjects() {
const projects = await fetchProjects()
return (
<SidebarMenu>
{projects.map((project) => (
<SidebarMenuItem key={project.name}>
<SidebarMenuButton render={<a href={project.url} />}>
<project.icon />
<span>{project.name}</span>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
)
}

View File

@@ -27,7 +27,7 @@ function NavigationMenu({
function NavigationMenuList({
className,
...props
}: NavigationMenuPrimitive.List.Props) {
}: React.ComponentPropsWithRef<typeof NavigationMenuPrimitive.List>) {
return (
<NavigationMenuPrimitive.List
data-slot="navigation-menu-list"
@@ -43,7 +43,7 @@ function NavigationMenuList({
function NavigationMenuItem({
className,
...props
}: NavigationMenuPrimitive.Item.Props) {
}: React.ComponentPropsWithRef<typeof NavigationMenuPrimitive.Item>) {
return (
<NavigationMenuPrimitive.Item
data-slot="navigation-menu-item"
@@ -146,7 +146,7 @@ function NavigationMenuLink({
function NavigationMenuIndicator({
className,
...props
}: NavigationMenuPrimitive.Icon.Props) {
}: React.ComponentPropsWithRef<typeof NavigationMenuPrimitive.Icon>) {
return (
<NavigationMenuPrimitive.Icon
data-slot="navigation-menu-indicator"

View File

@@ -0,0 +1,95 @@
"use client"
import * as React from "react"
import { Button } from "@/examples/radix/ui/button"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarInset,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/examples/radix/ui/sidebar"
import {
FrameIcon,
LifeBuoyIcon,
MapIcon,
PanelLeftCloseIcon,
PanelLeftOpenIcon,
PieChartIcon,
SendIcon,
} from "lucide-react"
const projects = [
{
name: "Design Engineering",
url: "#",
icon: FrameIcon,
},
{
name: "Sales & Marketing",
url: "#",
icon: PieChartIcon,
},
{
name: "Travel",
url: "#",
icon: MapIcon,
},
{
name: "Support",
url: "#",
icon: LifeBuoyIcon,
},
{
name: "Feedback",
url: "#",
icon: SendIcon,
},
]
export default function AppSidebar() {
const [open, setOpen] = React.useState(true)
return (
<SidebarProvider open={open} onOpenChange={setOpen}>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{projects.map((project) => (
<SidebarMenuItem key={project.name}>
<SidebarMenuButton asChild>
<a href={project.url}>
<project.icon />
<span>{project.name}</span>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
<SidebarInset>
<header className="flex h-12 items-center justify-between px-4">
<Button
onClick={() => setOpen((open) => !open)}
size="sm"
variant="ghost"
>
{open ? <PanelLeftCloseIcon /> : <PanelLeftOpenIcon />}
<span>{open ? "Close" : "Open"} Sidebar</span>
</Button>
</header>
</SidebarInset>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,83 @@
"use client"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarInset,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
SidebarTrigger,
} from "@/examples/radix/ui/sidebar"
import {
CalendarIcon,
HomeIcon,
InboxIcon,
SearchIcon,
SettingsIcon,
} from "lucide-react"
const items = [
{
title: "Home",
url: "#",
icon: HomeIcon,
},
{
title: "Inbox",
url: "#",
icon: InboxIcon,
},
{
title: "Calendar",
url: "#",
icon: CalendarIcon,
},
{
title: "Search",
url: "#",
icon: SearchIcon,
},
{
title: "Settings",
url: "#",
icon: SettingsIcon,
},
]
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Application</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{items.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton asChild>
<a href={item.url}>
<item.icon />
<span>{item.title}</span>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
<SidebarInset>
<header className="flex h-12 items-center justify-between px-4">
<SidebarTrigger />
</header>
</SidebarInset>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,65 @@
"use client"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/examples/radix/ui/dropdown-menu"
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarHeader,
SidebarInset,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
SidebarTrigger,
} from "@/examples/radix/ui/sidebar"
import { ChevronUpIcon } from "lucide-react"
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarHeader />
<SidebarContent />
<SidebarFooter>
<SidebarMenu>
<SidebarMenuItem>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<SidebarMenuButton className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground">
Username
<ChevronUpIcon className="ml-auto" />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent
side="top"
className="w-(--radix-popper-anchor-width)"
>
<DropdownMenuItem>
<span>Account</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>Billing</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>Sign out</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
</Sidebar>
<SidebarInset>
<header className="flex h-12 items-center justify-between px-4">
<SidebarTrigger />
</header>
</SidebarInset>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,70 @@
"use client"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupAction,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/examples/radix/ui/sidebar"
import { FrameIcon, MapIcon, PieChartIcon, PlusIcon } from "lucide-react"
import { toast, Toaster } from "sonner"
export default function AppSidebar() {
return (
<SidebarProvider>
<Toaster
position="bottom-left"
toastOptions={{
className: "ml-[160px]",
}}
/>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupAction
title="Add Project"
onClick={() => toast("You clicked the group action!")}
>
<PlusIcon /> <span className="sr-only">Add Project</span>
</SidebarGroupAction>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton asChild>
<a href="#">
<FrameIcon />
<span>Design Engineering</span>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton asChild>
<a href="#">
<PieChartIcon />
<span>Sales & Marketing</span>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton asChild>
<a href="#">
<MapIcon />
<span>Travel</span>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,61 @@
"use client"
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/examples/radix/ui/collapsible"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/examples/radix/ui/sidebar"
import { ChevronDownIcon, LifeBuoyIcon, SendIcon } from "lucide-react"
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<Collapsible defaultOpen className="group/collapsible">
<SidebarGroup>
<SidebarGroupLabel
asChild
className="hover:bg-sidebar-accent hover:text-sidebar-accent-foreground text-sm"
>
<CollapsibleTrigger>
Help
<ChevronDownIcon className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-180" />
</CollapsibleTrigger>
</SidebarGroupLabel>
<CollapsibleContent>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton>
<LifeBuoyIcon />
Support
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton>
<SendIcon />
Feedback
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</CollapsibleContent>
</SidebarGroup>
</Collapsible>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,44 @@
"use client"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/examples/radix/ui/sidebar"
import { LifeBuoyIcon, SendIcon } from "lucide-react"
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Help</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton>
<LifeBuoyIcon />
Support
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton>
<SendIcon />
Feedback
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,55 @@
"use client"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/examples/radix/ui/dropdown-menu"
import {
Sidebar,
SidebarHeader,
SidebarInset,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
SidebarTrigger,
} from "@/examples/radix/ui/sidebar"
import { ChevronDownIcon } from "lucide-react"
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarHeader>
<SidebarMenu>
<SidebarMenuItem>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<SidebarMenuButton className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground">
Select Workspace
<ChevronDownIcon className="ml-auto" />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-(--radix-popper-anchor-width)">
<DropdownMenuItem>
<span>Acme Inc</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>Acme Corp.</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
</Sidebar>
<SidebarInset>
<header className="flex h-12 items-center justify-between px-4">
<SidebarTrigger />
</header>
</SidebarInset>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,103 @@
"use client"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/examples/radix/ui/dropdown-menu"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuAction,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/examples/radix/ui/sidebar"
import {
FrameIcon,
LifeBuoyIcon,
MapIcon,
MoreHorizontalIcon,
PieChartIcon,
SendIcon,
} from "lucide-react"
const projects = [
{
name: "Design Engineering",
url: "#",
icon: FrameIcon,
},
{
name: "Sales & Marketing",
url: "#",
icon: PieChartIcon,
},
{
name: "Travel",
url: "#",
icon: MapIcon,
},
{
name: "Support",
url: "#",
icon: LifeBuoyIcon,
},
{
name: "Feedback",
url: "#",
icon: SendIcon,
},
]
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{projects.map((project) => (
<SidebarMenuItem key={project.name}>
<SidebarMenuButton
asChild
className="group-has-[[data-state=open]]/menu-item:bg-sidebar-accent"
>
<a href={project.url}>
<project.icon />
<span>{project.name}</span>
</a>
</SidebarMenuButton>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<SidebarMenuAction>
<MoreHorizontalIcon />
<span className="sr-only">More</span>
</SidebarMenuAction>
</DropdownMenuTrigger>
<DropdownMenuContent side="right" align="start">
<DropdownMenuItem>
<span>Edit Project</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>Delete Project</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,86 @@
"use client"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuBadge,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/examples/radix/ui/sidebar"
import {
FrameIcon,
LifeBuoyIcon,
MapIcon,
PieChartIcon,
SendIcon,
} from "lucide-react"
const projects = [
{
name: "Design Engineering",
url: "#",
icon: FrameIcon,
badge: "24",
},
{
name: "Sales & Marketing",
url: "#",
icon: PieChartIcon,
badge: "12",
},
{
name: "Travel",
url: "#",
icon: MapIcon,
badge: "3",
},
{
name: "Support",
url: "#",
icon: LifeBuoyIcon,
badge: "21",
},
{
name: "Feedback",
url: "#",
icon: SendIcon,
badge: "8",
},
]
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{projects.map((project) => (
<SidebarMenuItem key={project.name}>
<SidebarMenuButton
asChild
className="group-has-[[data-state=open]]/menu-item:bg-sidebar-accent"
>
<a href={project.url}>
<project.icon />
<span>{project.name}</span>
</a>
</SidebarMenuButton>
<SidebarMenuBadge>{project.badge}</SidebarMenuBadge>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,195 @@
"use client"
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/examples/radix/ui/collapsible"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSub,
SidebarMenuSubButton,
SidebarMenuSubItem,
SidebarProvider,
} from "@/examples/radix/ui/sidebar"
import { ChevronRightIcon } from "lucide-react"
const items = [
{
title: "Getting Started",
url: "#",
items: [
{
title: "Installation",
url: "#",
},
{
title: "Project Structure",
url: "#",
},
],
},
{
title: "Building Your Application",
url: "#",
items: [
{
title: "Routing",
url: "#",
},
{
title: "Data Fetching",
url: "#",
isActive: true,
},
{
title: "Rendering",
url: "#",
},
{
title: "Caching",
url: "#",
},
{
title: "Styling",
url: "#",
},
{
title: "Optimizing",
url: "#",
},
{
title: "Configuring",
url: "#",
},
{
title: "Testing",
url: "#",
},
{
title: "Authentication",
url: "#",
},
{
title: "Deploying",
url: "#",
},
{
title: "Upgrading",
url: "#",
},
{
title: "Examples",
url: "#",
},
],
},
{
title: "API Reference",
url: "#",
items: [
{
title: "Components",
url: "#",
},
{
title: "File Conventions",
url: "#",
},
{
title: "Functions",
url: "#",
},
{
title: "next.config.js Options",
url: "#",
},
{
title: "CLI",
url: "#",
},
{
title: "Edge Runtime",
url: "#",
},
],
},
{
title: "Architecture",
url: "#",
items: [
{
title: "Accessibility",
url: "#",
},
{
title: "Fast Refresh",
url: "#",
},
{
title: "Next.js Compiler",
url: "#",
},
{
title: "Supported Browsers",
url: "#",
},
{
title: "Turbopack",
url: "#",
},
],
},
]
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupContent>
<SidebarMenu>
{items.map((item, index) => (
<Collapsible
key={index}
className="group/collapsible"
defaultOpen={index === 0}
>
<SidebarMenuItem>
<CollapsibleTrigger asChild>
<SidebarMenuButton>
<span>{item.title}</span>
<ChevronRightIcon className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-90" />
</SidebarMenuButton>
</CollapsibleTrigger>
<CollapsibleContent>
<SidebarMenuSub>
{item.items.map((subItem, subIndex) => (
<SidebarMenuSubItem key={subIndex}>
<SidebarMenuSubButton asChild>
<a href={subItem.url}>
<span>{subItem.title}</span>
</a>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
))}
</SidebarMenuSub>
</CollapsibleContent>
</SidebarMenuItem>
</Collapsible>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,180 @@
"use client"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSub,
SidebarMenuSubButton,
SidebarMenuSubItem,
SidebarProvider,
} from "@/examples/radix/ui/sidebar"
const items = [
{
title: "Getting Started",
url: "#",
items: [
{
title: "Installation",
url: "#",
},
{
title: "Project Structure",
url: "#",
},
],
},
{
title: "Building Your Application",
url: "#",
items: [
{
title: "Routing",
url: "#",
},
{
title: "Data Fetching",
url: "#",
isActive: true,
},
{
title: "Rendering",
url: "#",
},
{
title: "Caching",
url: "#",
},
{
title: "Styling",
url: "#",
},
{
title: "Optimizing",
url: "#",
},
{
title: "Configuring",
url: "#",
},
{
title: "Testing",
url: "#",
},
{
title: "Authentication",
url: "#",
},
{
title: "Deploying",
url: "#",
},
{
title: "Upgrading",
url: "#",
},
{
title: "Examples",
url: "#",
},
],
},
{
title: "API Reference",
url: "#",
items: [
{
title: "Components",
url: "#",
},
{
title: "File Conventions",
url: "#",
},
{
title: "Functions",
url: "#",
},
{
title: "next.config.js Options",
url: "#",
},
{
title: "CLI",
url: "#",
},
{
title: "Edge Runtime",
url: "#",
},
],
},
{
title: "Architecture",
url: "#",
items: [
{
title: "Accessibility",
url: "#",
},
{
title: "Fast Refresh",
url: "#",
},
{
title: "Next.js Compiler",
url: "#",
},
{
title: "Supported Browsers",
url: "#",
},
{
title: "Turbopack",
url: "#",
},
],
},
]
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupContent>
<SidebarMenu>
{items.map((item, index) => (
<SidebarMenuItem key={index}>
<SidebarMenuButton asChild>
<a href={item.url}>
<span>{item.title}</span>
</a>
</SidebarMenuButton>
<SidebarMenuSub>
{item.items.map((subItem, subIndex) => (
<SidebarMenuSubItem key={subIndex}>
<SidebarMenuSubButton asChild>
<a href={subItem.url}>
<span>{subItem.title}</span>
</a>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
))}
</SidebarMenuSub>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,76 @@
"use client"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/examples/radix/ui/sidebar"
import {
FrameIcon,
LifeBuoyIcon,
MapIcon,
PieChartIcon,
SendIcon,
} from "lucide-react"
const projects = [
{
name: "Design Engineering",
url: "#",
icon: FrameIcon,
},
{
name: "Sales & Marketing",
url: "#",
icon: PieChartIcon,
},
{
name: "Travel",
url: "#",
icon: MapIcon,
},
{
name: "Support",
url: "#",
icon: LifeBuoyIcon,
},
{
name: "Feedback",
url: "#",
icon: SendIcon,
},
]
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{projects.map((project) => (
<SidebarMenuItem key={project.name}>
<SidebarMenuButton asChild>
<a href={project.url}>
<project.icon />
<span>{project.name}</span>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,109 @@
import * as React from "react"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSkeleton,
SidebarProvider,
} from "@/examples/radix/ui/sidebar"
import {
FrameIcon,
LifeBuoyIcon,
MapIcon,
PieChartIcon,
SendIcon,
} from "lucide-react"
const projects = [
{
name: "Design Engineering",
url: "#",
icon: FrameIcon,
badge: "24",
},
{
name: "Sales & Marketing",
url: "#",
icon: PieChartIcon,
badge: "12",
},
{
name: "Travel",
url: "#",
icon: MapIcon,
badge: "3",
},
{
name: "Support",
url: "#",
icon: LifeBuoyIcon,
badge: "21",
},
{
name: "Feedback",
url: "#",
icon: SendIcon,
badge: "8",
},
]
// Dummy fetch function.
async function fetchProjects() {
await new Promise((resolve) => setTimeout(resolve, 3000))
return projects
}
export default function AppSidebar() {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupContent>
<React.Suspense fallback={<NavProjectsSkeleton />}>
<NavProjects />
</React.Suspense>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}
function NavProjectsSkeleton() {
return (
<SidebarMenu>
{Array.from({ length: 5 }).map((_, index) => (
<SidebarMenuItem key={index}>
<SidebarMenuSkeleton showIcon />
</SidebarMenuItem>
))}
</SidebarMenu>
)
}
async function NavProjects() {
const projects = await fetchProjects()
return (
<SidebarMenu>
{projects.map((project) => (
<SidebarMenuItem key={project.name}>
<SidebarMenuButton asChild>
<a href={project.url}>
<project.icon />
<span>{project.name}</span>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
)
}

View File

@@ -3,6 +3,14 @@ export const legacyStyles = [
name: "new-york-v4",
title: "New York",
},
{
name: "base-nova",
title: "Base Nova",
},
{
name: "radix-nova",
title: "Radix Nova",
},
] as const
export type Style = (typeof legacyStyles)[number]

View File

@@ -27,7 +27,7 @@ function NavigationMenu({
function NavigationMenuList({
className,
...props
}: NavigationMenuPrimitive.List.Props) {
}: React.ComponentPropsWithRef<typeof NavigationMenuPrimitive.List>) {
return (
<NavigationMenuPrimitive.List
data-slot="navigation-menu-list"
@@ -43,7 +43,7 @@ function NavigationMenuList({
function NavigationMenuItem({
className,
...props
}: NavigationMenuPrimitive.Item.Props) {
}: React.ComponentPropsWithRef<typeof NavigationMenuPrimitive.Item>) {
return (
<NavigationMenuPrimitive.Item
data-slot="navigation-menu-item"
@@ -143,7 +143,7 @@ function NavigationMenuLink({
function NavigationMenuIndicator({
className,
...props
}: NavigationMenuPrimitive.Icon.Props) {
}: React.ComponentPropsWithRef<typeof NavigationMenuPrimitive.Icon>) {
return (
<NavigationMenuPrimitive.Icon
data-slot="navigation-menu-indicator"