snapshot of https://github.com/shadcn-ui/ui.git (main, 2026-09-15; blobs > 131072B omitted)
This commit is contained in:
@@ -0,0 +1,309 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import { NavUser } from "@/registry/bases/radix/blocks/sidebar-09/components/nav-user"
|
||||
import { Label } from "@/registry/bases/radix/ui/label"
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarHeader,
|
||||
SidebarInput,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
useSidebar,
|
||||
} from "@/registry/bases/radix/ui/sidebar"
|
||||
import { Switch } from "@/registry/bases/radix/ui/switch"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
// This is sample data
|
||||
const data = {
|
||||
user: {
|
||||
name: "shadcn",
|
||||
email: "m@example.com",
|
||||
avatar: "/avatars/shadcn.jpg",
|
||||
},
|
||||
navMain: [
|
||||
{
|
||||
title: "Inbox",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="InboxIcon"
|
||||
tabler="IconInbox"
|
||||
hugeicons="InboxIcon"
|
||||
phosphor="TrayIcon"
|
||||
remixicon="RiInboxLine"
|
||||
/>
|
||||
),
|
||||
isActive: true,
|
||||
},
|
||||
{
|
||||
title: "Drafts",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="FileIcon"
|
||||
tabler="IconFile"
|
||||
hugeicons="FileIcon"
|
||||
phosphor="FileIcon"
|
||||
remixicon="RiFileLine"
|
||||
/>
|
||||
),
|
||||
isActive: false,
|
||||
},
|
||||
{
|
||||
title: "Sent",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="SendIcon"
|
||||
tabler="IconSend"
|
||||
hugeicons="SentIcon"
|
||||
phosphor="PaperPlaneTiltIcon"
|
||||
remixicon="RiSendPlaneLine"
|
||||
/>
|
||||
),
|
||||
isActive: false,
|
||||
},
|
||||
{
|
||||
title: "Junk",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="ArchiveXIcon"
|
||||
tabler="IconArchiveOff"
|
||||
hugeicons="ArchiveIcon"
|
||||
phosphor="ArchiveIcon"
|
||||
remixicon="RiArchiveLine"
|
||||
/>
|
||||
),
|
||||
isActive: false,
|
||||
},
|
||||
{
|
||||
title: "Trash",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="Trash2Icon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="Delete02Icon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
),
|
||||
isActive: false,
|
||||
},
|
||||
],
|
||||
mails: [
|
||||
{
|
||||
name: "William Smith",
|
||||
email: "williamsmith@example.com",
|
||||
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: "alicesmith@example.com",
|
||||
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: "bobjohnson@example.com",
|
||||
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: "emilydavis@example.com",
|
||||
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: "michaelwilson@example.com",
|
||||
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: "sarahbrown@example.com",
|
||||
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: "davidlee@example.com",
|
||||
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: "oliviawilson@example.com",
|
||||
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: "jamesmartin@example.com",
|
||||
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: "sophiawhite@example.com",
|
||||
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 AppSidebar({ ...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">
|
||||
<IconPlaceholder
|
||||
lucide="TerminalIcon"
|
||||
tabler="IconCommand"
|
||||
hugeicons="CommandIcon"
|
||||
phosphor="CommandIcon"
|
||||
remixicon="RiCommandLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid flex-1 text-left text-sm leading-tight">
|
||||
<span className="truncate font-medium">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 border-b p-4 text-sm leading-tight whitespace-nowrap 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] text-xs whitespace-break-spaces">
|
||||
{mail.teaser}
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
</Sidebar>
|
||||
</Sidebar>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
AvatarImage,
|
||||
} from "@/registry/bases/radix/ui/avatar"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/dropdown-menu"
|
||||
import {
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
useSidebar,
|
||||
} from "@/registry/bases/radix/ui/sidebar"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
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-medium">{user.name}</span>
|
||||
<span className="truncate text-xs">{user.email}</span>
|
||||
</div>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronsUpDownIcon"
|
||||
tabler="IconSelector"
|
||||
hugeicons="UnfoldMoreIcon"
|
||||
phosphor="CaretUpDownIcon"
|
||||
remixicon="RiArrowUpDownLine"
|
||||
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-medium">{user.name}</span>
|
||||
<span className="truncate text-xs">{user.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="SparklesIcon"
|
||||
tabler="IconSparkles"
|
||||
hugeicons="SparklesIcon"
|
||||
phosphor="SparkleIcon"
|
||||
remixicon="RiSparklingLine"
|
||||
/>
|
||||
Upgrade to Pro
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheckIcon"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadgeIcon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
/>
|
||||
Account
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
Billing
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="BellIcon"
|
||||
tabler="IconBell"
|
||||
hugeicons="NotificationIcon"
|
||||
phosphor="BellIcon"
|
||||
remixicon="RiNotificationLine"
|
||||
/>
|
||||
Notifications
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="LogOutIcon"
|
||||
tabler="IconLogout"
|
||||
hugeicons="LogoutIcon"
|
||||
phosphor="SignOutIcon"
|
||||
remixicon="RiLogoutBoxLine"
|
||||
/>
|
||||
Log out
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user