diff --git a/apps/v4/app/(view)/view/[style]/[name]/page.tsx b/apps/v4/app/(view)/view/[style]/[name]/page.tsx index 77761346df..4bab7cad65 100644 --- a/apps/v4/app/(view)/view/[style]/[name]/page.tsx +++ b/apps/v4/app/(view)/view/[style]/[name]/page.tsx @@ -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 } diff --git a/apps/v4/components/component-preview.tsx b/apps/v4/components/component-preview.tsx index a983919ef1..693c5d1db9 100644 --- a/apps/v4/components/component-preview.tsx +++ b/apps/v4/components/component-preview.tsx @@ -29,14 +29,14 @@ export function ComponentPreview({ return (
{name} {name} - +
A sidebar that collapses to icons.
@@ -318,15 +314,8 @@ export function AppSidebar() { You should see something like this: -
- +
+
Your first sidebar.
@@ -545,14 +534,7 @@ Use the `SidebarHeader` component to add a sticky header to the sidebar. The following example adds a `` to the `SidebarHeader`.
- +
A sidebar header with a dropdown menu.
@@ -592,14 +574,7 @@ Use the `SidebarFooter` component to add a sticky footer to the sidebar. The following example adds a `` to the `SidebarFooter`.
- +
A sidebar footer with a dropdown menu.
@@ -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`.
- +
A sidebar group.
@@ -713,10 +681,7 @@ To make a `SidebarGroup` collapsible, wrap it in a `Collapsible`.
A collapsible sidebar group. @@ -756,10 +721,7 @@ Use the `SidebarGroupAction` component to add an action button to the `SidebarGr
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.
- +
A sidebar menu with a list of projects.
@@ -906,10 +861,7 @@ Here's an example of a `SidebarMenuAction` component rendering a `DropdownMenu`.
A sidebar menu action with a dropdown menu. @@ -952,10 +904,7 @@ Use `` and `` to render a submenu
A sidebar menu with a submenu. @@ -984,10 +933,7 @@ To make a `SidebarMenu` component collapsible, wrap it and the `SidebarMenuSub`
A collapsible sidebar menu. @@ -1019,10 +965,7 @@ The `SidebarMenuBadge` component is used to render a badge within a `SidebarMenu
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.
- +
A sidebar menu using React Server Components.
@@ -1274,10 +1210,7 @@ Use the `open` and `onOpenChange` props to control the sidebar.
A controlled sidebar. diff --git a/apps/v4/content/docs/components/radix/sidebar.mdx b/apps/v4/content/docs/components/radix/sidebar.mdx index 025db54271..a68b8e7c2e 100644 --- a/apps/v4/content/docs/components/radix/sidebar.mdx +++ b/apps/v4/content/docs/components/radix/sidebar.mdx @@ -321,7 +321,7 @@ export function AppSidebar() { You should see something like this: -
+
> = { 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> = { 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", diff --git a/apps/v4/examples/base/sidebar-controlled.tsx b/apps/v4/examples/base/sidebar-controlled.tsx new file mode 100644 index 0000000000..c472444c09 --- /dev/null +++ b/apps/v4/examples/base/sidebar-controlled.tsx @@ -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 ( + + + + + Projects + + + {projects.map((project) => ( + + }> + + {project.name} + + + ))} + + + + + + +
+ +
+
+
+ ) +} diff --git a/apps/v4/examples/base/sidebar-demo.tsx b/apps/v4/examples/base/sidebar-demo.tsx new file mode 100644 index 0000000000..25db4a2a2b --- /dev/null +++ b/apps/v4/examples/base/sidebar-demo.tsx @@ -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 ( + + + + + Application + + + {items.map((item) => ( + + }> + + {item.title} + + + ))} + + + + + + +
+ +
+
+
+ ) +} diff --git a/apps/v4/examples/base/sidebar-footer.tsx b/apps/v4/examples/base/sidebar-footer.tsx new file mode 100644 index 0000000000..003f6f980d --- /dev/null +++ b/apps/v4/examples/base/sidebar-footer.tsx @@ -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 ( + + + + + + + + + + } + > + Username + + + + + Account + + + Billing + + + Sign out + + + + + + + + +
+ +
+
+
+ ) +} diff --git a/apps/v4/examples/base/sidebar-group-action.tsx b/apps/v4/examples/base/sidebar-group-action.tsx new file mode 100644 index 0000000000..050b66842a --- /dev/null +++ b/apps/v4/examples/base/sidebar-group-action.tsx @@ -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 ( + + + + + + Projects + toast("You clicked the group action!")} + > + Add Project + + + + + }> + + Design Engineering + + + + }> + + Sales & Marketing + + + + }> + + Travel + + + + + + + + + ) +} diff --git a/apps/v4/examples/base/sidebar-group-collapsible.tsx b/apps/v4/examples/base/sidebar-group-collapsible.tsx new file mode 100644 index 0000000000..5fe16ad205 --- /dev/null +++ b/apps/v4/examples/base/sidebar-group-collapsible.tsx @@ -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 ( + + + + + + } + className="hover:bg-sidebar-accent hover:text-sidebar-accent-foreground text-sm" + > + Help + + + + + + + + + Support + + + + + + Feedback + + + + + + + + + + + ) +} diff --git a/apps/v4/examples/base/sidebar-group.tsx b/apps/v4/examples/base/sidebar-group.tsx new file mode 100644 index 0000000000..497158a794 --- /dev/null +++ b/apps/v4/examples/base/sidebar-group.tsx @@ -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 ( + + + + + Help + + + + + + Support + + + + + + Feedback + + + + + + + + + ) +} diff --git a/apps/v4/examples/base/sidebar-header.tsx b/apps/v4/examples/base/sidebar-header.tsx new file mode 100644 index 0000000000..2e5c4bd142 --- /dev/null +++ b/apps/v4/examples/base/sidebar-header.tsx @@ -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 ( + + + + + + + + } + > + Select Workspace + + + + + Acme Inc + + + Acme Corp. + + + + + + + + +
+ +
+
+
+ ) +} diff --git a/apps/v4/examples/base/sidebar-menu-action.tsx b/apps/v4/examples/base/sidebar-menu-action.tsx new file mode 100644 index 0000000000..77009ef61e --- /dev/null +++ b/apps/v4/examples/base/sidebar-menu-action.tsx @@ -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 ( + + + + + Projects + + + {projects.map((project) => ( + + } + className="group-has-[[data-state=open]]/menu-item:bg-sidebar-accent" + > + + {project.name} + + + }> + + More + + + + Edit Project + + + Delete Project + + + + + ))} + + + + + + + ) +} diff --git a/apps/v4/examples/base/sidebar-menu-badge.tsx b/apps/v4/examples/base/sidebar-menu-badge.tsx new file mode 100644 index 0000000000..54d4cd1451 --- /dev/null +++ b/apps/v4/examples/base/sidebar-menu-badge.tsx @@ -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 ( + + + + + Projects + + + {projects.map((project) => ( + + } + className="group-has-[[data-state=open]]/menu-item:bg-sidebar-accent" + > + + {project.name} + + {project.badge} + + ))} + + + + + + + ) +} diff --git a/apps/v4/examples/base/sidebar-menu-collapsible.tsx b/apps/v4/examples/base/sidebar-menu-collapsible.tsx new file mode 100644 index 0000000000..b404baf747 --- /dev/null +++ b/apps/v4/examples/base/sidebar-menu-collapsible.tsx @@ -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 ( + + + + + + + {items.map((item, index) => ( + + + }> + {item.title} + + + + + {item.items.map((subItem, subIndex) => ( + + } + > + {subItem.title} + + + ))} + + + + + ))} + + + + + + + ) +} diff --git a/apps/v4/examples/base/sidebar-menu-sub.tsx b/apps/v4/examples/base/sidebar-menu-sub.tsx new file mode 100644 index 0000000000..b39a1e3dbe --- /dev/null +++ b/apps/v4/examples/base/sidebar-menu-sub.tsx @@ -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 ( + + + + + + + {items.map((item, index) => ( + + }> + {item.title} + + + {item.items.map((subItem, subIndex) => ( + + } + > + {subItem.title} + + + ))} + + + ))} + + + + + + + ) +} diff --git a/apps/v4/examples/base/sidebar-menu.tsx b/apps/v4/examples/base/sidebar-menu.tsx new file mode 100644 index 0000000000..dc8b0362aa --- /dev/null +++ b/apps/v4/examples/base/sidebar-menu.tsx @@ -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 ( + + + + + Projects + + + {projects.map((project) => ( + + }> + + {project.name} + + + ))} + + + + + + + ) +} diff --git a/apps/v4/examples/base/sidebar-rsc.tsx b/apps/v4/examples/base/sidebar-rsc.tsx new file mode 100644 index 0000000000..f3e6029dd3 --- /dev/null +++ b/apps/v4/examples/base/sidebar-rsc.tsx @@ -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 ( + + + + + Projects + + }> + + + + + + + + ) +} + +function NavProjectsSkeleton() { + return ( + + {Array.from({ length: 5 }).map((_, index) => ( + + + + ))} + + ) +} + +async function NavProjects() { + const projects = await fetchProjects() + + return ( + + {projects.map((project) => ( + + }> + + {project.name} + + + ))} + + ) +} diff --git a/apps/v4/examples/base/ui/navigation-menu.tsx b/apps/v4/examples/base/ui/navigation-menu.tsx index ff81723570..28254365e2 100644 --- a/apps/v4/examples/base/ui/navigation-menu.tsx +++ b/apps/v4/examples/base/ui/navigation-menu.tsx @@ -27,7 +27,7 @@ function NavigationMenu({ function NavigationMenuList({ className, ...props -}: NavigationMenuPrimitive.List.Props) { +}: React.ComponentPropsWithRef) { return ( ) { return ( ) { return ( + + + + Projects + + + {projects.map((project) => ( + + + + + {project.name} + + + + ))} + + + + + + +
+ +
+
+ + ) +} diff --git a/apps/v4/examples/radix/sidebar-demo.tsx b/apps/v4/examples/radix/sidebar-demo.tsx new file mode 100644 index 0000000000..79b16a835f --- /dev/null +++ b/apps/v4/examples/radix/sidebar-demo.tsx @@ -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 ( + + + + + Application + + + {items.map((item) => ( + + + + + {item.title} + + + + ))} + + + + + + +
+ +
+
+
+ ) +} diff --git a/apps/v4/examples/radix/sidebar-footer.tsx b/apps/v4/examples/radix/sidebar-footer.tsx new file mode 100644 index 0000000000..1b4803d017 --- /dev/null +++ b/apps/v4/examples/radix/sidebar-footer.tsx @@ -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 ( + + + + + + + + + + + Username + + + + + + Account + + + Billing + + + Sign out + + + + + + + + +
+ +
+
+
+ ) +} diff --git a/apps/v4/examples/radix/sidebar-group-action.tsx b/apps/v4/examples/radix/sidebar-group-action.tsx new file mode 100644 index 0000000000..542435b0f0 --- /dev/null +++ b/apps/v4/examples/radix/sidebar-group-action.tsx @@ -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 ( + + + + + + Projects + toast("You clicked the group action!")} + > + Add Project + + + + + + + + Design Engineering + + + + + + + + Sales & Marketing + + + + + + + + Travel + + + + + + + + + + ) +} diff --git a/apps/v4/examples/radix/sidebar-group-collapsible.tsx b/apps/v4/examples/radix/sidebar-group-collapsible.tsx new file mode 100644 index 0000000000..419d19c64a --- /dev/null +++ b/apps/v4/examples/radix/sidebar-group-collapsible.tsx @@ -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 ( + + + + + + + + Help + + + + + + + + + + Support + + + + + + Feedback + + + + + + + + + + + ) +} diff --git a/apps/v4/examples/radix/sidebar-group.tsx b/apps/v4/examples/radix/sidebar-group.tsx new file mode 100644 index 0000000000..8e51c15392 --- /dev/null +++ b/apps/v4/examples/radix/sidebar-group.tsx @@ -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 ( + + + + + Help + + + + + + Support + + + + + + Feedback + + + + + + + + + ) +} diff --git a/apps/v4/examples/radix/sidebar-header.tsx b/apps/v4/examples/radix/sidebar-header.tsx new file mode 100644 index 0000000000..5cd9bc4563 --- /dev/null +++ b/apps/v4/examples/radix/sidebar-header.tsx @@ -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 ( + + + + + + + + + Select Workspace + + + + + + Acme Inc + + + Acme Corp. + + + + + + + + +
+ +
+
+
+ ) +} diff --git a/apps/v4/examples/radix/sidebar-menu-action.tsx b/apps/v4/examples/radix/sidebar-menu-action.tsx new file mode 100644 index 0000000000..602b847c82 --- /dev/null +++ b/apps/v4/examples/radix/sidebar-menu-action.tsx @@ -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 ( + + + + + Projects + + + {projects.map((project) => ( + + + + + {project.name} + + + + + + + More + + + + + Edit Project + + + Delete Project + + + + + ))} + + + + + + + ) +} diff --git a/apps/v4/examples/radix/sidebar-menu-badge.tsx b/apps/v4/examples/radix/sidebar-menu-badge.tsx new file mode 100644 index 0000000000..375c016fd4 --- /dev/null +++ b/apps/v4/examples/radix/sidebar-menu-badge.tsx @@ -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 ( + + + + + Projects + + + {projects.map((project) => ( + + + + + {project.name} + + + {project.badge} + + ))} + + + + + + + ) +} diff --git a/apps/v4/examples/radix/sidebar-menu-collapsible.tsx b/apps/v4/examples/radix/sidebar-menu-collapsible.tsx new file mode 100644 index 0000000000..c23c01db51 --- /dev/null +++ b/apps/v4/examples/radix/sidebar-menu-collapsible.tsx @@ -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 ( + + + + + + + {items.map((item, index) => ( + + + + + {item.title} + + + + + + {item.items.map((subItem, subIndex) => ( + + + + {subItem.title} + + + + ))} + + + + + ))} + + + + + + + ) +} diff --git a/apps/v4/examples/radix/sidebar-menu-sub.tsx b/apps/v4/examples/radix/sidebar-menu-sub.tsx new file mode 100644 index 0000000000..2746f9aa8d --- /dev/null +++ b/apps/v4/examples/radix/sidebar-menu-sub.tsx @@ -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 ( + + + + + + + {items.map((item, index) => ( + + + + {item.title} + + + + {item.items.map((subItem, subIndex) => ( + + + + {subItem.title} + + + + ))} + + + ))} + + + + + + + ) +} diff --git a/apps/v4/examples/radix/sidebar-menu.tsx b/apps/v4/examples/radix/sidebar-menu.tsx new file mode 100644 index 0000000000..124b9827b0 --- /dev/null +++ b/apps/v4/examples/radix/sidebar-menu.tsx @@ -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 ( + + + + + Projects + + + {projects.map((project) => ( + + + + + {project.name} + + + + ))} + + + + + + + ) +} diff --git a/apps/v4/examples/radix/sidebar-rsc.tsx b/apps/v4/examples/radix/sidebar-rsc.tsx new file mode 100644 index 0000000000..77f3f6beba --- /dev/null +++ b/apps/v4/examples/radix/sidebar-rsc.tsx @@ -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 ( + + + + + Projects + + }> + + + + + + + + ) +} + +function NavProjectsSkeleton() { + return ( + + {Array.from({ length: 5 }).map((_, index) => ( + + + + ))} + + ) +} + +async function NavProjects() { + const projects = await fetchProjects() + + return ( + + {projects.map((project) => ( + + + + + {project.name} + + + + ))} + + ) +} diff --git a/apps/v4/registry/_legacy-styles.ts b/apps/v4/registry/_legacy-styles.ts index c53d31b3b1..e58353db4b 100644 --- a/apps/v4/registry/_legacy-styles.ts +++ b/apps/v4/registry/_legacy-styles.ts @@ -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] diff --git a/apps/v4/registry/bases/base/ui/navigation-menu.tsx b/apps/v4/registry/bases/base/ui/navigation-menu.tsx index 5b1e350159..d8f66280af 100644 --- a/apps/v4/registry/bases/base/ui/navigation-menu.tsx +++ b/apps/v4/registry/bases/base/ui/navigation-menu.tsx @@ -27,7 +27,7 @@ function NavigationMenu({ function NavigationMenuList({ className, ...props -}: NavigationMenuPrimitive.List.Props) { +}: React.ComponentPropsWithRef) { return ( ) { return ( ) { return (