Spaces:
Sleeping
Sleeping
| import type { LucideIcon } from "lucide-react"; | |
| import { LogOut, UserCircle2 } from "lucide-react"; | |
| import { Button } from "@/components/ui/button"; | |
| import { | |
| Sidebar, | |
| SidebarContent, | |
| SidebarFooter, | |
| SidebarHeader, | |
| useSidebar, | |
| } from "@/components/ui/sidebar"; | |
| import { cn } from "@/lib/utils"; | |
| export type RoleSidebarItem<TMenu extends string> = { | |
| id: TMenu; | |
| label: string; | |
| icon: LucideIcon; | |
| }; | |
| type AppRoleSidebarProps<TMenu extends string> = { | |
| brandIcon: LucideIcon; | |
| brandTitle: string; | |
| menuItems: RoleSidebarItem<TMenu>[]; | |
| activeMenu: TMenu; | |
| onSelectMenu: (menu: TMenu) => void; | |
| userName: string; | |
| userRoleLabel: string; | |
| onLogout: () => void; | |
| }; | |
| export function AppRoleSidebar<TMenu extends string>({ | |
| brandIcon: BrandIcon, | |
| brandTitle, | |
| menuItems, | |
| activeMenu, | |
| onSelectMenu, | |
| userName, | |
| userRoleLabel, | |
| onLogout, | |
| }: AppRoleSidebarProps<TMenu>) { | |
| const { isMobile, setOpenMobile } = useSidebar(); | |
| return ( | |
| <Sidebar | |
| collapsible="offcanvas" | |
| className="bg-sidebar text-sidebar-foreground" | |
| > | |
| <SidebarHeader | |
| className="h-20 border-b border-sidebar-border px-5" | |
| > | |
| <div className="flex items-center gap-3"> | |
| <div className="flex size-8 items-center justify-center rounded-full bg-primary"> | |
| <BrandIcon className="size-4 text-primary-foreground" /> | |
| </div> | |
| <p className="text-xl font-semibold leading-none md:text-2xl"> | |
| {brandTitle} | |
| </p> | |
| </div> | |
| </SidebarHeader> | |
| <SidebarContent className="p-4"> | |
| <div className="space-y-2"> | |
| {menuItems.map((item) => { | |
| const isActive = activeMenu === item.id; | |
| return ( | |
| <Button | |
| key={item.id} | |
| type="button" | |
| variant={isActive ? "default" : "ghost"} | |
| onClick={() => { | |
| onSelectMenu(item.id); | |
| if (isMobile) setOpenMobile(false); | |
| }} | |
| className={cn( | |
| "h-10 w-full justify-start gap-2 px-3 text-left text-sm font-medium", | |
| isActive | |
| ? "bg-sidebar-primary text-sidebar-primary-foreground hover:bg-sidebar-primary/90" | |
| : "text-sidebar-foreground/90 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", | |
| )} | |
| > | |
| <item.icon className="size-4" /> | |
| <span>{item.label}</span> | |
| </Button> | |
| ); | |
| })} | |
| </div> | |
| </SidebarContent> | |
| <SidebarFooter className="border-t border-sidebar-border p-4"> | |
| <div className="mb-4 flex items-center gap-2 rounded-lg bg-sidebar-accent px-3 py-2"> | |
| <UserCircle2 className="size-5 text-sidebar-foreground/90" /> | |
| <div className="min-w-0"> | |
| <p className="line-clamp-1 text-sm font-semibold text-sidebar-foreground"> | |
| {userName} | |
| </p> | |
| <p className="text-xs text-sidebar-foreground/80"> | |
| {userRoleLabel} | |
| </p> | |
| </div> | |
| </div> | |
| <Button | |
| type="button" | |
| variant="ghost" | |
| onClick={onLogout} | |
| className="h-auto justify-start px-0 text-sm font-semibold text-destructive hover:bg-transparent hover:text-destructive/80" | |
| > | |
| <LogOut className="size-4" /> | |
| <span>Logout</span> | |
| </Button> | |
| </SidebarFooter> | |
| </Sidebar> | |
| ); | |
| } | |