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