Skip to content

Instantly share code, notes, and snippets.

@Grigore147
Forked from nickzelei/sidebar.tsx
Created August 25, 2025 01:09
Show Gist options
  • Save Grigore147/18ba080394d9344b681c4c3cc425b8ef to your computer and use it in GitHub Desktop.
Save Grigore147/18ba080394d9344b681c4c3cc425b8ef to your computer and use it in GitHub Desktop.

Revisions

  1. @nickzelei nickzelei created this gist May 21, 2025.
    773 changes: 773 additions & 0 deletions sidebar.tsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,773 @@
    import { cn } from '@/lib/utils'
    import { Slot } from '@radix-ui/react-slot'
    import { VariantProps, cva } from 'class-variance-authority'
    import { PanelLeftIcon } from 'lucide-react'
    import * as React from 'react'
    import { useIsMobile } from '../../lib/hooks/useMobile'
    import { Button } from './button'
    import { Input } from './input'
    import KeybindingTooltip from './KeybindingTooltip'
    import { Separator } from './separator'
    import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from './sheet'
    import { Skeleton } from './skeleton'
    import { TooltipContent, TooltipProvider } from './tooltip'

    const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
    const SIDEBAR_WIDTH = '15rem'
    const SIDEBAR_WIDTH_MOBILE = '18rem'
    const SIDEBAR_WIDTH_ICON = '3rem'
    const DEFAULT_KEYBOARD_SHORTCUT = 'b'

    type SidebarState = {
    isOpen: boolean
    isMobileOpen: boolean
    }

    type SidebarContextProps<T extends string> = {
    sidebars: Record<T, SidebarState>
    setSidebarState: (
    name: T,
    state: Partial<SidebarState> | ((prev: SidebarState) => Partial<SidebarState>)
    ) => void
    toggleSidebar: (name: T) => void
    isMobile: boolean
    }

    const SidebarContext = React.createContext<SidebarContextProps<any> | null>(null)

    function useSidebar<T extends string>(name: T) {
    const context = React.useContext(SidebarContext)
    if (!context) {
    throw new Error('useSidebar must be used within a SidebarProvider.')
    }

    const sidebarState = context.sidebars[name] ?? { isOpen: false, isMobileOpen: false }

    return {
    ...sidebarState,
    isMobile: context.isMobile,
    toggle: () => context.toggleSidebar(name),
    setState: (state: Partial<SidebarState>) => context.setSidebarState(name, state)
    }
    }

    function SidebarProvider<T extends string>({
    defaultOpen = 'all',
    sidebarNames,
    open: openProp,
    onOpenChange: setOpenProp,
    className,
    style,
    children,
    keyboardShortcuts,
    ...props
    }: React.ComponentProps<'div'> & {
    defaultOpen?: 'all' | T[]
    sidebarNames: readonly T[]
    open?: T[]
    onOpenChange?: (open: T[]) => void
    keyboardShortcuts?: Partial<Record<T, string>>
    }) {
    const isMobile = useIsMobile()

    // Initialize sidebar states
    const initialSidebars = React.useMemo(() => {
    const states: Record<T, SidebarState> = {} as Record<T, SidebarState>
    const defaultOpenState = defaultOpen === 'all' ? sidebarNames : defaultOpen

    sidebarNames.forEach((name) => {
    states[name] = {
    isOpen: defaultOpenState.includes(name),
    isMobileOpen: false
    }
    })
    return states
    }, [defaultOpen, sidebarNames])

    const [sidebars, setSidebars] = React.useState<Record<T, SidebarState>>(initialSidebars)

    // Update sidebars when openProp changes
    React.useEffect(() => {
    if (openProp) {
    setSidebars((prev) => {
    const next = { ...prev }
    sidebarNames.forEach((name) => {
    next[name] = {
    ...next[name],
    isOpen: openProp.includes(name)
    }
    })
    return next
    })
    }
    }, [openProp, sidebarNames])

    const setSidebarState = React.useCallback(
    (name: T, state: Partial<SidebarState> | ((prev: SidebarState) => Partial<SidebarState>)) => {
    setSidebars((prev) => {
    const next = { ...prev }
    const currentState = next[name] ?? { isOpen: false, isMobileOpen: false }
    const newState = typeof state === 'function' ? state(currentState) : state
    next[name] = { ...currentState, ...newState }

    // Update cookie
    const openState = Object.entries(next)
    .filter(([_, state]) => (state as SidebarState).isOpen)
    .map(([name]) => name as T)

    document.cookie = `${openState.map((sidebarName) => `${sidebarName}:state=${next[sidebarName].isOpen}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`).join('; ')}`

    // Call onOpenChange if provided
    if (setOpenProp) {
    setOpenProp(openState)
    }

    return next
    })
    },
    [setOpenProp]
    )

    const toggleSidebar = React.useCallback(
    (name: T) => {
    setSidebarState(name, (prev: SidebarState) => ({
    ...prev,
    isOpen: isMobile ? prev.isMobileOpen : !prev.isOpen,
    isMobileOpen: isMobile ? !prev.isMobileOpen : prev.isMobileOpen
    }))
    },
    [isMobile, setSidebarState]
    )

    // Add keyboard shortcuts
    React.useEffect(() => {
    const handleKeyDown = (event: KeyboardEvent) => {
    if (!(event.metaKey || event.ctrlKey)) return

    // Check each sidebar's shortcut
    Object.entries(keyboardShortcuts ?? {}).forEach(([name, shortcut]) => {
    if (event.key === shortcut) {
    event.preventDefault()
    toggleSidebar(name as T)
    }
    })

    // If no specific shortcuts are provided, use the default shortcut for all sidebars
    if (!keyboardShortcuts && event.key === DEFAULT_KEYBOARD_SHORTCUT) {
    event.preventDefault()
    sidebarNames.forEach((name) => toggleSidebar(name))
    }
    }

    window.addEventListener('keydown', handleKeyDown)
    return () => window.removeEventListener('keydown', handleKeyDown)
    }, [toggleSidebar, keyboardShortcuts, sidebarNames])

    const contextValue = React.useMemo<SidebarContextProps<T>>(
    () => ({
    sidebars,
    setSidebarState,
    toggleSidebar,
    isMobile
    }),
    [sidebars, setSidebarState, toggleSidebar, isMobile]
    )

    return (
    <SidebarContext.Provider value={contextValue}>
    <TooltipProvider delayDuration={0}>
    <div
    data-slot="sidebar-wrapper"
    style={
    {
    '--sidebar-width': SIDEBAR_WIDTH,
    '--sidebar-width-icon': SIDEBAR_WIDTH_ICON,
    ...style
    } as React.CSSProperties
    }
    className={cn(
    'group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full',
    className
    )}
    {...props}
    >
    {children}
    </div>
    </TooltipProvider>
    </SidebarContext.Provider>
    )
    }

    function Sidebar<T extends string>({
    name,
    side = 'left',
    variant = 'sidebar',
    collapsible = 'offcanvas',
    className,
    children,
    ...props
    }: React.ComponentProps<'div'> & {
    name: T
    side?: 'left' | 'right'
    variant?: 'sidebar' | 'floating' | 'inset'
    collapsible?: 'offcanvas' | 'icon' | 'none'
    }) {
    const { isMobile, isOpen, isMobileOpen, setState } = useSidebar(name)

    if (collapsible === 'none') {
    return (
    <div
    data-slot="sidebar"
    className={cn(
    'bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col',
    className
    )}
    {...props}
    >
    {children}
    </div>
    )
    }

    if (isMobile) {
    return (
    <Sheet
    open={isMobileOpen}
    onOpenChange={(open) => setState({ isMobileOpen: open })}
    {...props}
    >
    <SheetContent
    data-sidebar="sidebar"
    data-slot="sidebar"
    data-mobile="true"
    className="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
    style={
    {
    '--sidebar-width': SIDEBAR_WIDTH_MOBILE
    } as React.CSSProperties
    }
    side={side}
    >
    <SheetHeader className="sr-only">
    <SheetTitle>Sidebar</SheetTitle>
    <SheetDescription>Displays the mobile sidebar.</SheetDescription>
    </SheetHeader>
    <div className="flex h-full w-full flex-col">{children}</div>
    </SheetContent>
    </Sheet>
    )
    }

    return (
    <div
    className="group peer text-sidebar-foreground hidden md:block"
    data-state={isOpen ? 'expanded' : 'collapsed'}
    data-collapsible={isOpen ? '' : collapsible}
    data-variant={variant}
    data-side={side}
    data-slot="sidebar"
    >
    {/* This is what handles the sidebar gap on desktop */}
    <div
    data-slot="sidebar-gap"
    className={cn(
    'relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear',
    'group-data-[collapsible=offcanvas]:w-0',
    'group-data-[side=right]:rotate-180',
    variant === 'floating' || variant === 'inset'
    ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]'
    : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)'
    )}
    />
    <div
    data-slot="sidebar-container"
    className={cn(
    'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex',
    side === 'left'
    ? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
    : 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
    // Adjust the padding for floating and inset variants.
    variant === 'floating' || variant === 'inset'
    ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]'
    : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=right]:border-l',
    // group-data-[side=left]:border-r
    className
    )}
    {...props}
    >
    <div
    data-sidebar="sidebar"
    data-slot="sidebar-inner"
    className="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm"
    >
    {children}
    </div>
    </div>
    </div>
    )
    }

    function SidebarTrigger<T extends string>({
    className,
    onClick,
    name,
    icon = <PanelLeftIcon />,
    ...props
    }: React.ComponentProps<typeof Button> & {
    name: T
    icon?: React.ReactNode
    }) {
    const { toggle } = useSidebar(name)

    return (
    <Button
    data-sidebar="trigger"
    data-slot="sidebar-trigger"
    variant="ghost"
    size="icon"
    className={cn('size-6', className)}
    onClick={(event) => {
    onClick?.(event)
    toggle()
    }}
    {...props}
    >
    {icon}
    <span className="sr-only">Toggle Sidebar</span>
    </Button>
    )
    }

    function SidebarRail<T extends string>({
    className,
    name,
    ...props
    }: React.ComponentProps<'button'> & {
    name: T
    }) {
    const { toggle } = useSidebar(name)

    return (
    <button
    data-sidebar="rail"
    data-slot="sidebar-rail"
    aria-label="Toggle Sidebar"
    tabIndex={-1}
    onClick={() => toggle()}
    title="Toggle Sidebar"
    className={cn(
    'hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex',
    'in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize',
    '[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize',
    'hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full',
    '[[data-side=left][data-collapsible=offcanvas]_&]:-right-2',
    '[[data-side=right][data-collapsible=offcanvas]_&]:-left-2',
    className
    )}
    {...props}
    />
    )
    }

    function SidebarInset({ className, ...props }: React.ComponentProps<'main'>) {
    return (
    <main
    data-slot="sidebar-inset"
    className={cn(
    'bg-sidebar relative flex w-full flex-1 flex-col',
    '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 md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2',
    className
    )}
    {...props}
    />
    )
    }

    function SidebarInput({ className, ...props }: React.ComponentProps<typeof Input>) {
    return (
    <Input
    data-slot="sidebar-input"
    data-sidebar="input"
    className={cn('bg-background h-8 w-full shadow-none', className)}
    {...props}
    />
    )
    }

    function SidebarHeader({ className, ...props }: React.ComponentProps<'div'>) {
    return (
    <div
    data-slot="sidebar-header"
    data-sidebar="header"
    className={cn('flex flex-col gap-2 p-2', className)}
    {...props}
    />
    )
    }

    function SidebarFooter({ className, ...props }: React.ComponentProps<'div'>) {
    return (
    <div
    data-slot="sidebar-footer"
    data-sidebar="footer"
    className={cn('flex flex-col gap-2 p-2 items-center', className)}
    {...props}
    />
    )
    }

    function SidebarSeparator({ className, ...props }: React.ComponentProps<typeof Separator>) {
    return (
    <Separator
    data-slot="sidebar-separator"
    data-sidebar="separator"
    className={cn('bg-sidebar-border mx-2 w-auto', className)}
    {...props}
    />
    )
    }

    function SidebarContent({ className, ...props }: React.ComponentProps<'div'>) {
    return (
    <div
    data-slot="sidebar-content"
    data-sidebar="content"
    className={cn(
    'flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden',
    className
    )}
    {...props}
    />
    )
    }

    function SidebarGroup({ className, ...props }: React.ComponentProps<'div'>) {
    return (
    <div
    data-slot="sidebar-group"
    data-sidebar="group"
    className={cn('relative flex w-full min-w-0 flex-col items-center', className)}
    {...props}
    />
    )
    }

    function SidebarGroupLabel({
    className,
    asChild = false,
    ...props
    }: React.ComponentProps<'div'> & { asChild?: boolean }) {
    const Comp = asChild ? Slot : 'div'

    return (
    <Comp
    data-slot="sidebar-group-label"
    data-sidebar="group-label"
    className={cn(
    'text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
    'group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0',
    className
    )}
    {...props}
    />
    )
    }

    function SidebarGroupAction({
    className,
    asChild = false,
    ...props
    }: React.ComponentProps<'button'> & { asChild?: boolean }) {
    const Comp = asChild ? Slot : 'button'

    return (
    <Comp
    data-slot="sidebar-group-action"
    data-sidebar="group-action"
    className={cn(
    'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
    // Increases the hit area of the button on mobile.
    'after:absolute after:-inset-2 md:after:hidden',
    'group-data-[collapsible=icon]:hidden',
    className
    )}
    {...props}
    />
    )
    }

    function SidebarGroupContent({ className, ...props }: React.ComponentProps<'div'>) {
    return (
    <div
    data-slot="sidebar-group-content"
    data-sidebar="group-content"
    className={cn('w-full text-sm', className)}
    {...props}
    />
    )
    }

    function SidebarMenu({ className, ...props }: React.ComponentProps<'ul'>) {
    return (
    <ul
    data-slot="sidebar-menu"
    data-sidebar="menu"
    className={cn('flex w-full min-w-0 flex-col gap-1', className)}
    {...props}
    />
    )
    }

    function SidebarMenuItem({ className, ...props }: React.ComponentProps<'li'>) {
    return (
    <li
    data-slot="sidebar-menu-item"
    data-sidebar="menu-item"
    className={cn('group/menu-item relative', className)}
    {...props}
    />
    )
    }

    const sidebarMenuButtonVariants = cva(
    '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-gray-200 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',
    {
    variants: {
    variant: {
    default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
    outline:
    '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))]'
    },
    size: {
    default: 'h-8 text-sm',
    sm: 'h-7 text-xs',
    lg: 'h-12 text-sm group-data-[collapsible=icon]:p-0!'
    }
    },
    defaultVariants: {
    variant: 'default',
    size: 'default'
    }
    }
    )

    function SidebarMenuButton<T extends string>({
    asChild = false,
    isActive = false,
    variant = 'default',
    size = 'default',
    tooltip,
    className,
    name,
    ...props
    }: React.ComponentProps<'button'> & {
    asChild?: boolean
    isActive?: boolean
    tooltip?: string | React.ComponentProps<typeof TooltipContent>
    name: T
    } & VariantProps<typeof sidebarMenuButtonVariants>): React.ReactElement {
    const Comp = asChild ? Slot : 'button'
    const { isMobile, isOpen } = useSidebar(name)

    const button = (
    <Comp
    data-slot="sidebar-menu-button"
    data-sidebar="menu-button"
    data-size={size}
    data-active={isActive}
    className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
    {...props}
    />
    )

    if (!tooltip) {
    return button
    }

    if (typeof tooltip === 'string') {
    tooltip = {
    children: tooltip
    }
    }

    return (
    <KeybindingTooltip
    text={tooltip}
    side="right"
    align="center"
    hidden={!isOpen || isMobile}
    className=" hover:bg-gray-200 p-1 rounded mx-1 ml-1"
    >
    {button}
    </KeybindingTooltip>
    )
    }

    function SidebarMenuAction({
    className,
    asChild = false,
    showOnHover = false,
    ...props
    }: React.ComponentProps<'button'> & {
    asChild?: boolean
    showOnHover?: boolean
    }) {
    const Comp = asChild ? Slot : 'button'

    return (
    <Comp
    data-slot="sidebar-menu-action"
    data-sidebar="menu-action"
    className={cn(
    'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
    // Increases the hit area of the button on mobile.
    'after:absolute after:-inset-2 md:after:hidden',
    'peer-data-[size=sm]/menu-button:top-1',
    'peer-data-[size=default]/menu-button:top-1.5',
    'peer-data-[size=lg]/menu-button:top-2.5',
    'group-data-[collapsible=icon]:hidden',
    showOnHover &&
    'peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0',
    className
    )}
    {...props}
    />
    )
    }

    function SidebarMenuBadge({ className, ...props }: React.ComponentProps<'div'>) {
    return (
    <div
    data-slot="sidebar-menu-badge"
    data-sidebar="menu-badge"
    className={cn(
    'text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none',
    'peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground',
    'peer-data-[size=sm]/menu-button:top-1',
    'peer-data-[size=default]/menu-button:top-1.5',
    'peer-data-[size=lg]/menu-button:top-2.5',
    'group-data-[collapsible=icon]:hidden',
    className
    )}
    {...props}
    />
    )
    }

    function SidebarMenuSkeleton({
    className,
    showIcon = false,
    ...props
    }: React.ComponentProps<'div'> & {
    showIcon?: boolean
    }) {
    // Random width between 50 to 90%.
    const width = React.useMemo(() => {
    return `${Math.floor(Math.random() * 40) + 50}%`
    }, [])

    return (
    <div
    data-slot="sidebar-menu-skeleton"
    data-sidebar="menu-skeleton"
    className={cn('flex h-8 items-center gap-2 rounded-md px-2', className)}
    {...props}
    >
    {showIcon && <Skeleton className="size-4 rounded-md" data-sidebar="menu-skeleton-icon" />}
    <Skeleton
    className="h-4 max-w-(--skeleton-width) flex-1"
    data-sidebar="menu-skeleton-text"
    style={
    {
    '--skeleton-width': width
    } as React.CSSProperties
    }
    />
    </div>
    )
    }

    function SidebarMenuSub({ className, ...props }: React.ComponentProps<'ul'>) {
    return (
    <ul
    data-slot="sidebar-menu-sub"
    data-sidebar="menu-sub"
    className={cn(
    'border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5',
    'group-data-[collapsible=icon]:hidden',
    className
    )}
    {...props}
    />
    )
    }

    function SidebarMenuSubItem({ className, ...props }: React.ComponentProps<'li'>) {
    return (
    <li
    data-slot="sidebar-menu-sub-item"
    data-sidebar="menu-sub-item"
    className={cn('group/menu-sub-item relative', className)}
    {...props}
    />
    )
    }

    function SidebarMenuSubButton({
    asChild = false,
    size = 'md',
    isActive = false,
    className,
    ...props
    }: React.ComponentProps<'a'> & {
    asChild?: boolean
    size?: 'sm' | 'md'
    isActive?: boolean
    }) {
    const Comp = asChild ? Slot : 'a'

    return (
    <Comp
    data-slot="sidebar-menu-sub-button"
    data-sidebar="menu-sub-button"
    data-size={size}
    data-active={isActive}
    className={cn(
    'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 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',
    'data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground',
    size === 'sm' && 'text-xs',
    size === 'md' && 'text-sm',
    'group-data-[collapsible=icon]:hidden',
    className
    )}
    {...props}
    />
    )
    }

    export {
    Sidebar,
    SidebarContent,
    SidebarFooter,
    SidebarGroup,
    SidebarGroupAction,
    SidebarGroupContent,
    SidebarGroupLabel,
    SidebarHeader,
    SidebarInput,
    SidebarInset,
    SidebarMenu,
    SidebarMenuAction,
    SidebarMenuBadge,
    SidebarMenuButton,
    SidebarMenuItem,
    SidebarMenuSkeleton,
    SidebarMenuSub,
    SidebarMenuSubButton,
    SidebarMenuSubItem,
    SidebarProvider,
    SidebarRail,
    SidebarSeparator,
    SidebarTrigger,
    useSidebar
    }