mirror of
https://github.com/hanzoai/shadcn.git
synced 2026-11-03 03:18:52 +00:00
Squash merge of shadcn-ui/ui main branch into hanzo/ui, bringing in: - [email protected] through [email protected] releases - New apps/v4 directory structure - Registry system improvements and MCP server - Framework support (Vue, Svelte, React Native) - New templates (vite-app, monorepo-next, laravel) - Zod 4 compatibility (scoped override for zod@>4) - Test fixture corrections for alias resolution All 867 merge conflicts resolved preserving Hanzo customizations. 1020/1020 shadcn tests pass.
164 lines
4.1 KiB
TypeScript
164 lines
4.1 KiB
TypeScript
"use client"
|
|
|
|
import * as React from "react"
|
|
|
|
import {
|
|
Collapsible,
|
|
CollapsibleContent,
|
|
CollapsibleTrigger,
|
|
} from "@/registry/bases/base/ui/collapsible"
|
|
import {
|
|
Sidebar,
|
|
SidebarContent,
|
|
SidebarGroup,
|
|
SidebarGroupContent,
|
|
SidebarGroupLabel,
|
|
SidebarMenu,
|
|
SidebarMenuBadge,
|
|
SidebarMenuButton,
|
|
SidebarMenuItem,
|
|
SidebarMenuSub,
|
|
SidebarRail,
|
|
} from "@/registry/bases/base/ui/sidebar"
|
|
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
|
|
|
// This is sample data.
|
|
const data = {
|
|
changes: [
|
|
{
|
|
file: "README.md",
|
|
state: "M",
|
|
},
|
|
{
|
|
file: "api/hello/route.ts",
|
|
state: "U",
|
|
},
|
|
{
|
|
file: "app/layout.tsx",
|
|
state: "M",
|
|
},
|
|
],
|
|
tree: [
|
|
[
|
|
"app",
|
|
[
|
|
"api",
|
|
["hello", ["route.ts"]],
|
|
"page.tsx",
|
|
"layout.tsx",
|
|
["blog", ["page.tsx"]],
|
|
],
|
|
],
|
|
[
|
|
"components",
|
|
["ui", "button.tsx", "card.tsx"],
|
|
"header.tsx",
|
|
"footer.tsx",
|
|
],
|
|
["lib", ["util.ts"]],
|
|
["public", "favicon.ico", "vercel.svg"],
|
|
".eslintrc.json",
|
|
".gitignore",
|
|
"next.config.js",
|
|
"tailwind.config.js",
|
|
"package.json",
|
|
"README.md",
|
|
],
|
|
}
|
|
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
|
return (
|
|
<Sidebar {...props}>
|
|
<SidebarContent>
|
|
<SidebarGroup>
|
|
<SidebarGroupLabel>Changes</SidebarGroupLabel>
|
|
<SidebarGroupContent>
|
|
<SidebarMenu>
|
|
{data.changes.map((item, index) => (
|
|
<SidebarMenuItem key={index}>
|
|
<SidebarMenuButton>
|
|
<IconPlaceholder
|
|
lucide="FileIcon"
|
|
tabler="IconFile"
|
|
hugeicons="FileIcon"
|
|
phosphor="FileIcon"
|
|
remixicon="RiFileLine"
|
|
/>
|
|
{item.file}
|
|
</SidebarMenuButton>
|
|
<SidebarMenuBadge>{item.state}</SidebarMenuBadge>
|
|
</SidebarMenuItem>
|
|
))}
|
|
</SidebarMenu>
|
|
</SidebarGroupContent>
|
|
</SidebarGroup>
|
|
<SidebarGroup>
|
|
<SidebarGroupLabel>Files</SidebarGroupLabel>
|
|
<SidebarGroupContent>
|
|
<SidebarMenu>
|
|
{data.tree.map((item, index) => (
|
|
<Tree key={index} item={item} />
|
|
))}
|
|
</SidebarMenu>
|
|
</SidebarGroupContent>
|
|
</SidebarGroup>
|
|
</SidebarContent>
|
|
<SidebarRail />
|
|
</Sidebar>
|
|
)
|
|
}
|
|
type TreeItem = string | TreeItem[]
|
|
function Tree({ item }: { item: TreeItem }) {
|
|
const [name, ...items] = Array.isArray(item) ? item : [item]
|
|
if (!items.length) {
|
|
return (
|
|
<SidebarMenuButton
|
|
isActive={name === "button.tsx"}
|
|
className="data-[active=true]:bg-transparent"
|
|
>
|
|
<IconPlaceholder
|
|
lucide="FileIcon"
|
|
tabler="IconFile"
|
|
hugeicons="FileIcon"
|
|
phosphor="FileIcon"
|
|
remixicon="RiFileLine"
|
|
/>
|
|
{name}
|
|
</SidebarMenuButton>
|
|
)
|
|
}
|
|
return (
|
|
<SidebarMenuItem>
|
|
<Collapsible
|
|
className="group/collapsible [&[data-state=open]>button>svg:first-child]:rotate-90"
|
|
defaultOpen={name === "components" || name === "ui"}
|
|
>
|
|
<SidebarMenuButton render={<CollapsibleTrigger />}>
|
|
<IconPlaceholder
|
|
lucide="ChevronRightIcon"
|
|
tabler="IconChevronRight"
|
|
hugeicons="ArrowRight01Icon"
|
|
phosphor="CaretRightIcon"
|
|
remixicon="RiArrowRightSLine"
|
|
className="transition-transform"
|
|
/>
|
|
<IconPlaceholder
|
|
lucide="FolderIcon"
|
|
tabler="IconFolder"
|
|
hugeicons="FolderIcon"
|
|
phosphor="FolderIcon"
|
|
remixicon="RiFolderLine"
|
|
/>
|
|
{name}
|
|
</SidebarMenuButton>
|
|
<CollapsibleContent>
|
|
<SidebarMenuSub>
|
|
{items.map((subItem, index) => (
|
|
<Tree key={index} item={subItem} />
|
|
))}
|
|
</SidebarMenuSub>
|
|
</CollapsibleContent>
|
|
</Collapsible>
|
|
</SidebarMenuItem>
|
|
)
|
|
}
|