mirror of
https://github.com/hanzoai/shadcn.git
synced 2026-10-30 18:22:59 +00:00
Fixed deployment issues for GitHub Pages static export: Server Component Fixes: - Added 'use client' to all login blocks (10 files) - Added 'use client' to all signup blocks (10 files) - Added 'use client' to all sidebar blocks (25 files) - Added 'use client' to all OTP blocks (10 files) - Fixed VersionSwitcher/SearchForm naming in sidebar-02 Registry Structure Fixes: - Updated getRegistryItem() to use Index[style][name] pattern - Updated getRegistryComponent() to accept style parameter - Removed problematic Zod validation in blocks.ts - Fixed null to undefined conversion in block metadata Build Compatibility: - Disabled Shiki syntax highlighting for static export - Added HTML fallback for code blocks Result: All 353 static pages now generate successfully
425 lines
13 KiB
TypeScript
425 lines
13 KiB
TypeScript
"use client"
|
|
|
|
import * as React from "react"
|
|
import {
|
|
ArchiveX,
|
|
BadgeCheck,
|
|
Bell,
|
|
ChevronsUpDown,
|
|
Command,
|
|
CreditCard,
|
|
File,
|
|
Inbox,
|
|
LogOut,
|
|
Send,
|
|
Sparkles,
|
|
Trash2,
|
|
} from "lucide-react"
|
|
|
|
import {
|
|
Avatar,
|
|
AvatarFallback,
|
|
AvatarImage,
|
|
} from "@/registry/default/ui/avatar"
|
|
import {
|
|
Breadcrumb,
|
|
BreadcrumbItem,
|
|
BreadcrumbLink,
|
|
BreadcrumbList,
|
|
BreadcrumbPage,
|
|
BreadcrumbSeparator,
|
|
} from "@/registry/default/ui/breadcrumb"
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuGroup,
|
|
DropdownMenuItem,
|
|
DropdownMenuLabel,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from "@/registry/default/ui/dropdown-menu"
|
|
import { Label } from "@/registry/default/ui/label"
|
|
import { Separator } from "@/registry/default/ui/separator"
|
|
import {
|
|
Sidebar,
|
|
SidebarContent,
|
|
SidebarFooter,
|
|
SidebarGroup,
|
|
SidebarGroupContent,
|
|
SidebarHeader,
|
|
SidebarInput,
|
|
SidebarInset,
|
|
SidebarMenu,
|
|
SidebarMenuButton,
|
|
SidebarMenuItem,
|
|
SidebarProvider,
|
|
SidebarTrigger,
|
|
useSidebar,
|
|
} from "@/registry/default/ui/sidebar"
|
|
import { Switch } from "@/registry/default/ui/switch"
|
|
|
|
export default function Page() {
|
|
return (
|
|
<SidebarProvider
|
|
style={
|
|
{
|
|
"--sidebar-width": "350px",
|
|
} as React.CSSProperties
|
|
}
|
|
>
|
|
<AppSidebar09 />
|
|
<SidebarInset>
|
|
<header className="sticky top-0 flex shrink-0 items-center gap-2 border-b bg-background p-4">
|
|
<SidebarTrigger className="-ml-1" />
|
|
<Separator orientation="vertical" className="mr-2 h-4" />
|
|
<Breadcrumb>
|
|
<BreadcrumbList>
|
|
<BreadcrumbItem className="hidden md:block">
|
|
<BreadcrumbLink href="#">All Inboxes</BreadcrumbLink>
|
|
</BreadcrumbItem>
|
|
<BreadcrumbSeparator className="hidden md:block" />
|
|
<BreadcrumbItem>
|
|
<BreadcrumbPage>Inbox</BreadcrumbPage>
|
|
</BreadcrumbItem>
|
|
</BreadcrumbList>
|
|
</Breadcrumb>
|
|
</header>
|
|
<div className="flex flex-1 flex-col gap-4 p-4">
|
|
{Array.from({ length: 24 }).map((_, index) => (
|
|
<div
|
|
key={index}
|
|
className="aspect-video h-12 w-full rounded-lg bg-muted/50"
|
|
/>
|
|
))}
|
|
</div>
|
|
</SidebarInset>
|
|
</SidebarProvider>
|
|
)
|
|
}
|
|
|
|
// This is sample data
|
|
const data = {
|
|
user: {
|
|
name: "hanzo",
|
|
email: "[email protected]",
|
|
avatar: "/avatars/hanzo.jpg",
|
|
},
|
|
navMain: [
|
|
{
|
|
title: "Inbox",
|
|
url: "#",
|
|
icon: Inbox,
|
|
isActive: true,
|
|
},
|
|
{
|
|
title: "Drafts",
|
|
url: "#",
|
|
icon: File,
|
|
isActive: false,
|
|
},
|
|
{
|
|
title: "Sent",
|
|
url: "#",
|
|
icon: Send,
|
|
isActive: false,
|
|
},
|
|
{
|
|
title: "Junk",
|
|
url: "#",
|
|
icon: ArchiveX,
|
|
isActive: false,
|
|
},
|
|
{
|
|
title: "Trash",
|
|
url: "#",
|
|
icon: Trash2,
|
|
isActive: false,
|
|
},
|
|
],
|
|
mails: [
|
|
{
|
|
name: "William Smith",
|
|
email: "[email protected]",
|
|
subject: "Meeting Tomorrow",
|
|
date: "09:34 AM",
|
|
teaser:
|
|
"Hi team, just a reminder about our meeting tomorrow at 10 AM.\nPlease come prepared with your project updates.",
|
|
},
|
|
{
|
|
name: "Alice Smith",
|
|
email: "[email protected]",
|
|
subject: "Re: Project Update",
|
|
date: "Yesterday",
|
|
teaser:
|
|
"Thanks for the update. The progress looks great so far.\nLet's schedule a call to discuss the next steps.",
|
|
},
|
|
{
|
|
name: "Bob Johnson",
|
|
email: "[email protected]",
|
|
subject: "Weekend Plans",
|
|
date: "2 days ago",
|
|
teaser:
|
|
"Hey everyone! I'm thinking of organizing a team outing this weekend.\nWould you be interested in a hiking trip or a beach day?",
|
|
},
|
|
{
|
|
name: "Emily Davis",
|
|
email: "[email protected]",
|
|
subject: "Re: Question about Budget",
|
|
date: "2 days ago",
|
|
teaser:
|
|
"I've reviewed the budget numbers you sent over.\nCan we set up a quick call to discuss some potential adjustments?",
|
|
},
|
|
{
|
|
name: "Michael Wilson",
|
|
email: "[email protected]",
|
|
subject: "Important Announcement",
|
|
date: "1 week ago",
|
|
teaser:
|
|
"Please join us for an all-hands meeting this Friday at 3 PM.\nWe have some exciting news to share about the company's future.",
|
|
},
|
|
{
|
|
name: "Sarah Brown",
|
|
email: "[email protected]",
|
|
subject: "Re: Feedback on Proposal",
|
|
date: "1 week ago",
|
|
teaser:
|
|
"Thank you for sending over the proposal. I've reviewed it and have some thoughts.\nCould we schedule a meeting to discuss my feedback in detail?",
|
|
},
|
|
{
|
|
name: "David Lee",
|
|
email: "[email protected]",
|
|
subject: "New Project Idea",
|
|
date: "1 week ago",
|
|
teaser:
|
|
"I've been brainstorming and came up with an interesting project concept.\nDo you have time this week to discuss its potential impact and feasibility?",
|
|
},
|
|
{
|
|
name: "Olivia Wilson",
|
|
email: "[email protected]",
|
|
subject: "Vacation Plans",
|
|
date: "1 week ago",
|
|
teaser:
|
|
"Just a heads up that I'll be taking a two-week vacation next month.\nI'll make sure all my projects are up to date before I leave.",
|
|
},
|
|
{
|
|
name: "James Martin",
|
|
email: "[email protected]",
|
|
subject: "Re: Conference Registration",
|
|
date: "1 week ago",
|
|
teaser:
|
|
"I've completed the registration for the upcoming tech conference.\nLet me know if you need any additional information from my end.",
|
|
},
|
|
{
|
|
name: "Sophia White",
|
|
email: "[email protected]",
|
|
subject: "Team Dinner",
|
|
date: "1 week ago",
|
|
teaser:
|
|
"To celebrate our recent project success, I'd like to organize a team dinner.\nAre you available next Friday evening? Please let me know your preferences.",
|
|
},
|
|
],
|
|
}
|
|
|
|
export function AppSidebar09({
|
|
...props
|
|
}: React.ComponentProps<typeof Sidebar>) {
|
|
// Note: I'm using state to show active item.
|
|
// IRL you should use the url/router.
|
|
const [activeItem, setActiveItem] = React.useState(data.navMain[0])
|
|
const [mails, setMails] = React.useState(data.mails)
|
|
const { setOpen } = useSidebar()
|
|
|
|
return (
|
|
<Sidebar
|
|
collapsible="icon"
|
|
className="overflow-hidden [&>[data-sidebar=sidebar]]:flex-row"
|
|
{...props}
|
|
>
|
|
{/* This is the first sidebar */}
|
|
{/* We disable collapsible and adjust width to icon. */}
|
|
{/* This will make the sidebar appear as icons. */}
|
|
<Sidebar
|
|
collapsible="none"
|
|
className="!w-[calc(var(--sidebar-width-icon)_+_1px)] border-r"
|
|
>
|
|
<SidebarHeader>
|
|
<SidebarMenu>
|
|
<SidebarMenuItem>
|
|
<SidebarMenuButton size="lg" asChild className="md:h-8 md:p-0">
|
|
<a href="#">
|
|
<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
|
|
<Command className="size-4" />
|
|
</div>
|
|
<div className="grid flex-1 text-left text-sm leading-tight">
|
|
<span className="truncate font-semibold">Acme Inc</span>
|
|
<span className="truncate text-xs">Enterprise</span>
|
|
</div>
|
|
</a>
|
|
</SidebarMenuButton>
|
|
</SidebarMenuItem>
|
|
</SidebarMenu>
|
|
</SidebarHeader>
|
|
<SidebarContent>
|
|
<SidebarGroup>
|
|
<SidebarGroupContent className="px-1.5 md:px-0">
|
|
<SidebarMenu>
|
|
{data.navMain.map((item) => (
|
|
<SidebarMenuItem key={item.title}>
|
|
<SidebarMenuButton
|
|
tooltip={{
|
|
children: item.title,
|
|
hidden: false,
|
|
}}
|
|
onClick={() => {
|
|
setActiveItem(item)
|
|
const mail = data.mails.sort(() => Math.random() - 0.5)
|
|
setMails(
|
|
mail.slice(
|
|
0,
|
|
Math.max(5, Math.floor(Math.random() * 10) + 1)
|
|
)
|
|
)
|
|
setOpen(true)
|
|
}}
|
|
isActive={activeItem?.title === item.title}
|
|
className="px-2.5 md:px-2"
|
|
>
|
|
<item.icon />
|
|
<span>{item.title}</span>
|
|
</SidebarMenuButton>
|
|
</SidebarMenuItem>
|
|
))}
|
|
</SidebarMenu>
|
|
</SidebarGroupContent>
|
|
</SidebarGroup>
|
|
</SidebarContent>
|
|
<SidebarFooter>
|
|
<NavUser user={data.user} />
|
|
</SidebarFooter>
|
|
</Sidebar>
|
|
|
|
{/* This is the second sidebar */}
|
|
{/* We disable collapsible and let it fill remaining space */}
|
|
<Sidebar collapsible="none" className="hidden flex-1 md:flex">
|
|
<SidebarHeader className="gap-3.5 border-b p-4">
|
|
<div className="flex w-full items-center justify-between">
|
|
<div className="text-base font-medium text-foreground">
|
|
{activeItem?.title}
|
|
</div>
|
|
<Label className="flex items-center gap-2 text-sm">
|
|
<span>Unreads</span>
|
|
<Switch className="shadow-none" />
|
|
</Label>
|
|
</div>
|
|
<SidebarInput placeholder="Type to search..." />
|
|
</SidebarHeader>
|
|
<SidebarContent>
|
|
<SidebarGroup className="px-0">
|
|
<SidebarGroupContent>
|
|
{mails.map((mail) => (
|
|
<a
|
|
href="#"
|
|
key={mail.email}
|
|
className="flex flex-col items-start gap-2 whitespace-nowrap border-b p-4 text-sm leading-tight last:border-b-0 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
|
|
>
|
|
<div className="flex w-full items-center gap-2">
|
|
<span>{mail.name}</span>{" "}
|
|
<span className="ml-auto text-xs">{mail.date}</span>
|
|
</div>
|
|
<span className="font-medium">{mail.subject}</span>
|
|
<span className="line-clamp-2 w-[260px] whitespace-break-spaces text-xs">
|
|
{mail.teaser}
|
|
</span>
|
|
</a>
|
|
))}
|
|
</SidebarGroupContent>
|
|
</SidebarGroup>
|
|
</SidebarContent>
|
|
</Sidebar>
|
|
</Sidebar>
|
|
)
|
|
}
|
|
|
|
export function NavUser({
|
|
user,
|
|
}: {
|
|
user: {
|
|
name: string
|
|
email: string
|
|
avatar: string
|
|
}
|
|
}) {
|
|
const { isMobile } = useSidebar()
|
|
|
|
return (
|
|
<SidebarMenu>
|
|
<SidebarMenuItem>
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<SidebarMenuButton
|
|
size="lg"
|
|
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground md:h-8 md:p-0"
|
|
>
|
|
<Avatar className="h-8 w-8 rounded-lg">
|
|
<AvatarImage src={user.avatar} alt={user.name} />
|
|
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
|
</Avatar>
|
|
<div className="grid flex-1 text-left text-sm leading-tight">
|
|
<span className="truncate font-semibold">{user.name}</span>
|
|
<span className="truncate text-xs">{user.email}</span>
|
|
</div>
|
|
<ChevronsUpDown className="ml-auto size-4" />
|
|
</SidebarMenuButton>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent
|
|
className="w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg"
|
|
side={isMobile ? "bottom" : "right"}
|
|
align="end"
|
|
sideOffset={4}
|
|
>
|
|
<DropdownMenuLabel className="p-0 font-normal">
|
|
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
|
|
<Avatar className="h-8 w-8 rounded-lg">
|
|
<AvatarImage src={user.avatar} alt={user.name} />
|
|
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
|
</Avatar>
|
|
<div className="grid flex-1 text-left text-sm leading-tight">
|
|
<span className="truncate font-semibold">{user.name}</span>
|
|
<span className="truncate text-xs">{user.email}</span>
|
|
</div>
|
|
</div>
|
|
</DropdownMenuLabel>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuGroup>
|
|
<DropdownMenuItem>
|
|
<Sparkles />
|
|
Upgrade to Pro
|
|
</DropdownMenuItem>
|
|
</DropdownMenuGroup>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuGroup>
|
|
<DropdownMenuItem>
|
|
<BadgeCheck />
|
|
Account
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem>
|
|
<CreditCard />
|
|
Billing
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem>
|
|
<Bell />
|
|
Notifications
|
|
</DropdownMenuItem>
|
|
</DropdownMenuGroup>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem>
|
|
<LogOut />
|
|
Log out
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</SidebarMenuItem>
|
|
</SidebarMenu>
|
|
)
|
|
}
|