A quick vibe-coded site to test response times of PLC.directory mirrors (over 3 attempts)
1import * as React from "react";
2import { Slot } from "@radix-ui/react-slot";
3import { VariantProps, cva } from "class-variance-authority";
4import { PanelLeft } from "lucide-react";
5
6import { useIsMobile } from "@/hooks/use-mobile";
7import { cn } from "@/lib/utils";
8import { Button } from "@/components/ui/button";
9import { Input } from "@/components/ui/input";
10import { Separator } from "@/components/ui/separator";
11import { Sheet, SheetContent } from "@/components/ui/sheet";
12import { Skeleton } from "@/components/ui/skeleton";
13import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
14
15const SIDEBAR_COOKIE_NAME = "sidebar:state";
16const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
17const SIDEBAR_WIDTH = "16rem";
18const SIDEBAR_WIDTH_MOBILE = "18rem";
19const SIDEBAR_WIDTH_ICON = "3rem";
20const SIDEBAR_KEYBOARD_SHORTCUT = "b";
21
22type SidebarContext = {
23 state: "expanded" | "collapsed";
24 open: boolean;
25 setOpen: (open: boolean) => void;
26 openMobile: boolean;
27 setOpenMobile: (open: boolean) => void;
28 isMobile: boolean;
29 toggleSidebar: () => void;
30};
31
32const SidebarContext = React.createContext<SidebarContext | null>(null);
33
34function useSidebar() {
35 const context = React.useContext(SidebarContext);
36 if (!context) {
37 throw new Error("useSidebar must be used within a SidebarProvider.");
38 }
39
40 return context;
41}
42
43const SidebarProvider = React.forwardRef<
44 HTMLDivElement,
45 React.ComponentProps<"div"> & {
46 defaultOpen?: boolean;
47 open?: boolean;
48 onOpenChange?: (open: boolean) => void;
49 }
50>(({ defaultOpen = true, open: openProp, onOpenChange: setOpenProp, className, style, children, ...props }, ref) => {
51 const isMobile = useIsMobile();
52 const [openMobile, setOpenMobile] = React.useState(false);
53
54 // This is the internal state of the sidebar.
55 // We use openProp and setOpenProp for control from outside the component.
56 const [_open, _setOpen] = React.useState(defaultOpen);
57 const open = openProp ?? _open;
58 const setOpen = React.useCallback(
59 (value: boolean | ((value: boolean) => boolean)) => {
60 const openState = typeof value === "function" ? value(open) : value;
61 if (setOpenProp) {
62 setOpenProp(openState);
63 } else {
64 _setOpen(openState);
65 }
66
67 // This sets the cookie to keep the sidebar state.
68 document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
69 },
70 [setOpenProp, open],
71 );
72
73 // Helper to toggle the sidebar.
74 const toggleSidebar = React.useCallback(() => {
75 return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
76 }, [isMobile, setOpen, setOpenMobile]);
77
78 // Adds a keyboard shortcut to toggle the sidebar.
79 React.useEffect(() => {
80 const handleKeyDown = (event: KeyboardEvent) => {
81 if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
82 event.preventDefault();
83 toggleSidebar();
84 }
85 };
86
87 window.addEventListener("keydown", handleKeyDown);
88 return () => window.removeEventListener("keydown", handleKeyDown);
89 }, [toggleSidebar]);
90
91 // We add a state so that we can do data-state="expanded" or "collapsed".
92 // This makes it easier to style the sidebar with Tailwind classes.
93 const state = open ? "expanded" : "collapsed";
94
95 const contextValue = React.useMemo<SidebarContext>(
96 () => ({
97 state,
98 open,
99 setOpen,
100 isMobile,
101 openMobile,
102 setOpenMobile,
103 toggleSidebar,
104 }),
105 [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],
106 );
107
108 return (
109 <SidebarContext.Provider value={contextValue}>
110 <TooltipProvider delayDuration={0}>
111 <div
112 style={
113 {
114 "--sidebar-width": SIDEBAR_WIDTH,
115 "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
116 ...style,
117 } as React.CSSProperties
118 }
119 className={cn("group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar", className)}
120 ref={ref}
121 {...props}
122 >
123 {children}
124 </div>
125 </TooltipProvider>
126 </SidebarContext.Provider>
127 );
128});
129SidebarProvider.displayName = "SidebarProvider";
130
131const Sidebar = React.forwardRef<
132 HTMLDivElement,
133 React.ComponentProps<"div"> & {
134 side?: "left" | "right";
135 variant?: "sidebar" | "floating" | "inset";
136 collapsible?: "offcanvas" | "icon" | "none";
137 }
138>(({ side = "left", variant = "sidebar", collapsible = "offcanvas", className, children, ...props }, ref) => {
139 const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
140
141 if (collapsible === "none") {
142 return (
143 <div
144 className={cn("flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground", className)}
145 ref={ref}
146 {...props}
147 >
148 {children}
149 </div>
150 );
151 }
152
153 if (isMobile) {
154 return (
155 <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
156 <SheetContent
157 data-sidebar="sidebar"
158 data-mobile="true"
159 className="w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
160 style={
161 {
162 "--sidebar-width": SIDEBAR_WIDTH_MOBILE,
163 } as React.CSSProperties
164 }
165 side={side}
166 >
167 <div className="flex h-full w-full flex-col">{children}</div>
168 </SheetContent>
169 </Sheet>
170 );
171 }
172
173 return (
174 <div
175 ref={ref}
176 className="group peer hidden text-sidebar-foreground md:block"
177 data-state={state}
178 data-collapsible={state === "collapsed" ? collapsible : ""}
179 data-variant={variant}
180 data-side={side}
181 >
182 {/* This is what handles the sidebar gap on desktop */}
183 <div
184 className={cn(
185 "relative h-svh w-[--sidebar-width] bg-transparent transition-[width] duration-200 ease-linear",
186 "group-data-[collapsible=offcanvas]:w-0",
187 "group-data-[side=right]:rotate-180",
188 variant === "floating" || variant === "inset"
189 ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]"
190 : "group-data-[collapsible=icon]:w-[--sidebar-width-icon]",
191 )}
192 />
193 <div
194 className={cn(
195 "fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex",
196 side === "left"
197 ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
198 : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
199 // Adjust the padding for floating and inset variants.
200 variant === "floating" || variant === "inset"
201 ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]"
202 : "group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l",
203 className,
204 )}
205 {...props}
206 >
207 <div
208 data-sidebar="sidebar"
209 className="flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow"
210 >
211 {children}
212 </div>
213 </div>
214 </div>
215 );
216});
217Sidebar.displayName = "Sidebar";
218
219const SidebarTrigger = React.forwardRef<React.ElementRef<typeof Button>, React.ComponentProps<typeof Button>>(
220 ({ className, onClick, ...props }, ref) => {
221 const { toggleSidebar } = useSidebar();
222
223 return (
224 <Button
225 ref={ref}
226 data-sidebar="trigger"
227 variant="ghost"
228 size="icon"
229 className={cn("h-7 w-7", className)}
230 onClick={(event) => {
231 onClick?.(event);
232 toggleSidebar();
233 }}
234 {...props}
235 >
236 <PanelLeft />
237 <span className="sr-only">Toggle Sidebar</span>
238 </Button>
239 );
240 },
241);
242SidebarTrigger.displayName = "SidebarTrigger";
243
244const SidebarRail = React.forwardRef<HTMLButtonElement, React.ComponentProps<"button">>(
245 ({ className, ...props }, ref) => {
246 const { toggleSidebar } = useSidebar();
247
248 return (
249 <button
250 ref={ref}
251 data-sidebar="rail"
252 aria-label="Toggle Sidebar"
253 tabIndex={-1}
254 onClick={toggleSidebar}
255 title="Toggle Sidebar"
256 className={cn(
257 "absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] group-data-[side=left]:-right-4 group-data-[side=right]:left-0 hover:after:bg-sidebar-border sm:flex",
258 "[[data-side=left]_&]:cursor-w-resize [[data-side=right]_&]:cursor-e-resize",
259 "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
260 "group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-sidebar",
261 "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
262 "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
263 className,
264 )}
265 {...props}
266 />
267 );
268 },
269);
270SidebarRail.displayName = "SidebarRail";
271
272const SidebarInset = React.forwardRef<HTMLDivElement, React.ComponentProps<"main">>(({ className, ...props }, ref) => {
273 return (
274 <main
275 ref={ref}
276 className={cn(
277 "relative flex min-h-svh flex-1 flex-col bg-background",
278 "peer-data-[variant=inset]:min-h-[calc(100svh-theme(spacing.4))] md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow",
279 className,
280 )}
281 {...props}
282 />
283 );
284});
285SidebarInset.displayName = "SidebarInset";
286
287const SidebarInput = React.forwardRef<React.ElementRef<typeof Input>, React.ComponentProps<typeof Input>>(
288 ({ className, ...props }, ref) => {
289 return (
290 <Input
291 ref={ref}
292 data-sidebar="input"
293 className={cn(
294 "h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring",
295 className,
296 )}
297 {...props}
298 />
299 );
300 },
301);
302SidebarInput.displayName = "SidebarInput";
303
304const SidebarHeader = React.forwardRef<HTMLDivElement, React.ComponentProps<"div">>(({ className, ...props }, ref) => {
305 return <div ref={ref} data-sidebar="header" className={cn("flex flex-col gap-2 p-2", className)} {...props} />;
306});
307SidebarHeader.displayName = "SidebarHeader";
308
309const SidebarFooter = React.forwardRef<HTMLDivElement, React.ComponentProps<"div">>(({ className, ...props }, ref) => {
310 return <div ref={ref} data-sidebar="footer" className={cn("flex flex-col gap-2 p-2", className)} {...props} />;
311});
312SidebarFooter.displayName = "SidebarFooter";
313
314const SidebarSeparator = React.forwardRef<React.ElementRef<typeof Separator>, React.ComponentProps<typeof Separator>>(
315 ({ className, ...props }, ref) => {
316 return (
317 <Separator
318 ref={ref}
319 data-sidebar="separator"
320 className={cn("mx-2 w-auto bg-sidebar-border", className)}
321 {...props}
322 />
323 );
324 },
325);
326SidebarSeparator.displayName = "SidebarSeparator";
327
328const SidebarContent = React.forwardRef<HTMLDivElement, React.ComponentProps<"div">>(({ className, ...props }, ref) => {
329 return (
330 <div
331 ref={ref}
332 data-sidebar="content"
333 className={cn(
334 "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
335 className,
336 )}
337 {...props}
338 />
339 );
340});
341SidebarContent.displayName = "SidebarContent";
342
343const SidebarGroup = React.forwardRef<HTMLDivElement, React.ComponentProps<"div">>(({ className, ...props }, ref) => {
344 return (
345 <div
346 ref={ref}
347 data-sidebar="group"
348 className={cn("relative flex w-full min-w-0 flex-col p-2", className)}
349 {...props}
350 />
351 );
352});
353SidebarGroup.displayName = "SidebarGroup";
354
355const SidebarGroupLabel = React.forwardRef<HTMLDivElement, React.ComponentProps<"div"> & { asChild?: boolean }>(
356 ({ className, asChild = false, ...props }, ref) => {
357 const Comp = asChild ? Slot : "div";
358
359 return (
360 <Comp
361 ref={ref}
362 data-sidebar="group-label"
363 className={cn(
364 "flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opa] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
365 "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
366 className,
367 )}
368 {...props}
369 />
370 );
371 },
372);
373SidebarGroupLabel.displayName = "SidebarGroupLabel";
374
375const SidebarGroupAction = React.forwardRef<HTMLButtonElement, React.ComponentProps<"button"> & { asChild?: boolean }>(
376 ({ className, asChild = false, ...props }, ref) => {
377 const Comp = asChild ? Slot : "button";
378
379 return (
380 <Comp
381 ref={ref}
382 data-sidebar="group-action"
383 className={cn(
384 "absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
385 // Increases the hit area of the button on mobile.
386 "after:absolute after:-inset-2 after:md:hidden",
387 "group-data-[collapsible=icon]:hidden",
388 className,
389 )}
390 {...props}
391 />
392 );
393 },
394);
395SidebarGroupAction.displayName = "SidebarGroupAction";
396
397const SidebarGroupContent = React.forwardRef<HTMLDivElement, React.ComponentProps<"div">>(
398 ({ className, ...props }, ref) => (
399 <div ref={ref} data-sidebar="group-content" className={cn("w-full text-sm", className)} {...props} />
400 ),
401);
402SidebarGroupContent.displayName = "SidebarGroupContent";
403
404const SidebarMenu = React.forwardRef<HTMLUListElement, React.ComponentProps<"ul">>(({ className, ...props }, ref) => (
405 <ul ref={ref} data-sidebar="menu" className={cn("flex w-full min-w-0 flex-col gap-1", className)} {...props} />
406));
407SidebarMenu.displayName = "SidebarMenu";
408
409const SidebarMenuItem = React.forwardRef<HTMLLIElement, React.ComponentProps<"li">>(({ className, ...props }, ref) => (
410 <li ref={ref} data-sidebar="menu-item" className={cn("group/menu-item relative", className)} {...props} />
411));
412SidebarMenuItem.displayName = "SidebarMenuItem";
413
414const sidebarMenuButtonVariants = cva(
415 "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
416 {
417 variants: {
418 variant: {
419 default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
420 outline:
421 "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
422 },
423 size: {
424 default: "h-8 text-sm",
425 sm: "h-7 text-xs",
426 lg: "h-12 text-sm group-data-[collapsible=icon]:!p-0",
427 },
428 },
429 defaultVariants: {
430 variant: "default",
431 size: "default",
432 },
433 },
434);
435
436const SidebarMenuButton = React.forwardRef<
437 HTMLButtonElement,
438 React.ComponentProps<"button"> & {
439 asChild?: boolean;
440 isActive?: boolean;
441 tooltip?: string | React.ComponentProps<typeof TooltipContent>;
442 } & VariantProps<typeof sidebarMenuButtonVariants>
443>(({ asChild = false, isActive = false, variant = "default", size = "default", tooltip, className, ...props }, ref) => {
444 const Comp = asChild ? Slot : "button";
445 const { isMobile, state } = useSidebar();
446
447 const button = (
448 <Comp
449 ref={ref}
450 data-sidebar="menu-button"
451 data-size={size}
452 data-active={isActive}
453 className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
454 {...props}
455 />
456 );
457
458 if (!tooltip) {
459 return button;
460 }
461
462 if (typeof tooltip === "string") {
463 tooltip = {
464 children: tooltip,
465 };
466 }
467
468 return (
469 <Tooltip>
470 <TooltipTrigger asChild>{button}</TooltipTrigger>
471 <TooltipContent side="right" align="center" hidden={state !== "collapsed" || isMobile} {...tooltip} />
472 </Tooltip>
473 );
474});
475SidebarMenuButton.displayName = "SidebarMenuButton";
476
477const SidebarMenuAction = React.forwardRef<
478 HTMLButtonElement,
479 React.ComponentProps<"button"> & {
480 asChild?: boolean;
481 showOnHover?: boolean;
482 }
483>(({ className, asChild = false, showOnHover = false, ...props }, ref) => {
484 const Comp = asChild ? Slot : "button";
485
486 return (
487 <Comp
488 ref={ref}
489 data-sidebar="menu-action"
490 className={cn(
491 "absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform peer-hover/menu-button:text-sidebar-accent-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
492 // Increases the hit area of the button on mobile.
493 "after:absolute after:-inset-2 after:md:hidden",
494 "peer-data-[size=sm]/menu-button:top-1",
495 "peer-data-[size=default]/menu-button:top-1.5",
496 "peer-data-[size=lg]/menu-button:top-2.5",
497 "group-data-[collapsible=icon]:hidden",
498 showOnHover &&
499 "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0",
500 className,
501 )}
502 {...props}
503 />
504 );
505});
506SidebarMenuAction.displayName = "SidebarMenuAction";
507
508const SidebarMenuBadge = React.forwardRef<HTMLDivElement, React.ComponentProps<"div">>(
509 ({ className, ...props }, ref) => (
510 <div
511 ref={ref}
512 data-sidebar="menu-badge"
513 className={cn(
514 "pointer-events-none absolute right-1 flex h-5 min-w-5 select-none items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums text-sidebar-foreground",
515 "peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
516 "peer-data-[size=sm]/menu-button:top-1",
517 "peer-data-[size=default]/menu-button:top-1.5",
518 "peer-data-[size=lg]/menu-button:top-2.5",
519 "group-data-[collapsible=icon]:hidden",
520 className,
521 )}
522 {...props}
523 />
524 ),
525);
526SidebarMenuBadge.displayName = "SidebarMenuBadge";
527
528const SidebarMenuSkeleton = React.forwardRef<
529 HTMLDivElement,
530 React.ComponentProps<"div"> & {
531 showIcon?: boolean;
532 }
533>(({ className, showIcon = false, ...props }, ref) => {
534 // Random width between 50 to 90%.
535 const width = React.useMemo(() => {
536 return `${Math.floor(Math.random() * 40) + 50}%`;
537 }, []);
538
539 return (
540 <div
541 ref={ref}
542 data-sidebar="menu-skeleton"
543 className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)}
544 {...props}
545 >
546 {showIcon && <Skeleton className="size-4 rounded-md" data-sidebar="menu-skeleton-icon" />}
547 <Skeleton
548 className="h-4 max-w-[--skeleton-width] flex-1"
549 data-sidebar="menu-skeleton-text"
550 style={
551 {
552 "--skeleton-width": width,
553 } as React.CSSProperties
554 }
555 />
556 </div>
557 );
558});
559SidebarMenuSkeleton.displayName = "SidebarMenuSkeleton";
560
561const SidebarMenuSub = React.forwardRef<HTMLUListElement, React.ComponentProps<"ul">>(
562 ({ className, ...props }, ref) => (
563 <ul
564 ref={ref}
565 data-sidebar="menu-sub"
566 className={cn(
567 "mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5",
568 "group-data-[collapsible=icon]:hidden",
569 className,
570 )}
571 {...props}
572 />
573 ),
574);
575SidebarMenuSub.displayName = "SidebarMenuSub";
576
577const SidebarMenuSubItem = React.forwardRef<HTMLLIElement, React.ComponentProps<"li">>(({ ...props }, ref) => (
578 <li ref={ref} {...props} />
579));
580SidebarMenuSubItem.displayName = "SidebarMenuSubItem";
581
582const SidebarMenuSubButton = React.forwardRef<
583 HTMLAnchorElement,
584 React.ComponentProps<"a"> & {
585 asChild?: boolean;
586 size?: "sm" | "md";
587 isActive?: boolean;
588 }
589>(({ asChild = false, size = "md", isActive, className, ...props }, ref) => {
590 const Comp = asChild ? Slot : "a";
591
592 return (
593 <Comp
594 ref={ref}
595 data-sidebar="menu-sub-button"
596 data-size={size}
597 data-active={isActive}
598 className={cn(
599 "flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-none ring-sidebar-ring aria-disabled:pointer-events-none aria-disabled:opacity-50 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground",
600 "data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground",
601 size === "sm" && "text-xs",
602 size === "md" && "text-sm",
603 "group-data-[collapsible=icon]:hidden",
604 className,
605 )}
606 {...props}
607 />
608 );
609});
610SidebarMenuSubButton.displayName = "SidebarMenuSubButton";
611
612export {
613 Sidebar,
614 SidebarContent,
615 SidebarFooter,
616 SidebarGroup,
617 SidebarGroupAction,
618 SidebarGroupContent,
619 SidebarGroupLabel,
620 SidebarHeader,
621 SidebarInput,
622 SidebarInset,
623 SidebarMenu,
624 SidebarMenuAction,
625 SidebarMenuBadge,
626 SidebarMenuButton,
627 SidebarMenuItem,
628 SidebarMenuSkeleton,
629 SidebarMenuSub,
630 SidebarMenuSubButton,
631 SidebarMenuSubItem,
632 SidebarProvider,
633 SidebarRail,
634 SidebarSeparator,
635 SidebarTrigger,
636 useSidebar,
637};