"use client" import * as React from "react" import { Slot } from "@radix-ui/react-slot" import { cva, type VariantProps } from "class-variance-authority" import { PanelLeft } from "lucide-react" import { cn } from "@/lib/utils" import { Button } from "./button" import { Input } from "./input" import { Separator } from "./separator" import { Drawer as Sheet, DrawerContent as SheetContent } from "./drawer" import { Skeleton } from "./skeleton" import { Tooltip } from "./tooltip" const SIDEBAR_WIDTH = "16rem" const SIDEBAR_WIDTH_ICON = "3rem" const SIDEBAR_WIDTH_MOBILE = "18rem" const MOBILE_BREAKPOINT = "(max-width: 767px)" type SidebarContextValue = { state: "expanded" | "collapsed" open: boolean setOpen: (open: boolean) => void openMobile: boolean setOpenMobile: (open: boolean) => void isMobile: boolean toggleSidebar: () => void } const SidebarContext = React.createContext(null) function useIsMobile() { const [isMobile, setIsMobile] = React.useState(false) React.useEffect(() => { const media = window.matchMedia(MOBILE_BREAKPOINT) const update = () => setIsMobile(media.matches) update() media.addEventListener("change", update) return () => media.removeEventListener("change", update) }, []) return isMobile } function useSidebar() { const context = React.useContext(SidebarContext) if (!context) { throw new Error("useSidebar must be used within a SidebarProvider.") } return context } function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange: setOpenProp, className, style, children, ...props }: React.ComponentProps<"div"> & { defaultOpen?: boolean open?: boolean onOpenChange?: (open: boolean) => void }) { const isMobile = useIsMobile() const [openMobile, setOpenMobile] = React.useState(false) const [_open, _setOpen] = React.useState(defaultOpen) const open = openProp ?? _open const setOpen = React.useCallback( (value: boolean) => { setOpenProp?.(value) if (openProp === undefined) _setOpen(value) }, [openProp, setOpenProp] ) const toggleSidebar = React.useCallback(() => { if (isMobile) { setOpenMobile((value) => !value) return } setOpen(!open) }, [isMobile, open, setOpen]) const state = open ? "expanded" : "collapsed" const contextValue = React.useMemo( () => ({ state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar, }), [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar] ) return (
{children}
) } function Sidebar({ side = "left", variant = "sidebar", collapsible = "offcanvas", className, children, ...props }: React.ComponentProps<"div"> & { side?: "left" | "right" variant?: "sidebar" | "floating" | "inset" collapsible?: "offcanvas" | "icon" | "none" }) { const { isMobile, state, openMobile, setOpenMobile } = useSidebar() if (collapsible === "none") { return (
{children}
) } if (isMobile) { return (
{children}
) } return (
) } function SidebarTrigger({ className, onClick, children, ...props }: Omit, "children" | "variant" | "size"> & { children?: React.ReactNode }) { const { toggleSidebar } = useSidebar() return ( ) } function SidebarRail({ className, ...props }: React.ComponentProps<"button">) { const { toggleSidebar } = useSidebar() return (