{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "sidebar", "type": "registry:ui", "title": "Sidebar", "description": "Blinkist Sidebar Component", "dependencies": [ "@radix-ui/react-slot", "class-variance-authority", "lucide-react", "@radix-ui/react-separator", "@radix-ui/react-tooltip" ], "registryDependencies": [ "theme", "button", "input", "separator", "skeleton", "tooltip" ], "files": [ { "path": "components/ui/sidebar.tsx", "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { type VariantProps, cva } from \"class-variance-authority\"\nimport { PanelLeft } from \"lucide-react\"\n\nimport { useIsMobile } from \"@/hooks/use-mobile\"\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\nimport { Input } from \"@/components/ui/input\"\nimport { Separator } from \"@/components/ui/separator\"\nimport { Skeleton } from \"@/components/ui/skeleton\"\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"@/components/ui/tooltip\"\n\nconst SIDEBAR_COOKIE_NAME = \"sidebar:state\"\nconst SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7\nconst SIDEBAR_WIDTH = \"16rem\"\nconst SIDEBAR_WIDTH_MOBILE = \"18rem\"\nconst SIDEBAR_WIDTH_ICON = \"3rem\"\nconst SIDEBAR_KEYBOARD_SHORTCUT = \"b\"\n\ntype SidebarContext = {\n state: \"expanded\" | \"collapsed\"\n open: boolean\n setOpen: (open: boolean) => void\n openMobile: boolean\n setOpenMobile: (open: boolean) => void\n isMobile: boolean\n toggleSidebar: () => void\n}\n\nconst SidebarContext = React.createContext(null)\n\nfunction useSidebar() {\n const context = React.useContext(SidebarContext)\n if (!context) {\n throw new Error(\"useSidebar must be used within a SidebarProvider.\")\n }\n\n return context\n}\n\nconst SidebarProvider = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & {\n defaultOpen?: boolean\n open?: boolean\n onOpenChange?: (open: boolean) => void\n }\n>(({ defaultOpen = true, open: openProp, onOpenChange: setOpenProp, className, style, children, ...props }, ref) => {\n const isMobile = useIsMobile()\n const [openMobile, setOpenMobile] = React.useState(false)\n\n // This is the internal state of the sidebar.\n // We use openProp and setOpenProp for control from outside the component.\n const [_open, _setOpen] = React.useState(defaultOpen)\n const open = openProp ?? _open\n const setOpen = React.useCallback(\n (value: boolean | ((value: boolean) => boolean)) => {\n const openState = typeof value === \"function\" ? value(open) : value\n if (setOpenProp) {\n setOpenProp(openState)\n } else {\n _setOpen(openState)\n }\n\n // This sets the cookie to keep the sidebar state.\n document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`\n },\n [setOpenProp, open],\n )\n\n // Helper to toggle the sidebar.\n const toggleSidebar = React.useCallback(() => {\n return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)\n }, [isMobile, setOpen, setOpenMobile])\n\n // Adds a keyboard shortcut to toggle the sidebar.\n React.useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n toggleSidebar()\n }\n }\n\n window.addEventListener(\"keydown\", handleKeyDown)\n return () => window.removeEventListener(\"keydown\", handleKeyDown)\n }, [toggleSidebar])\n\n // We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n // This makes it easier to style the sidebar with Tailwind classes.\n const state = open ? \"expanded\" : \"collapsed\"\n\n const contextValue = React.useMemo(\n () => ({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n }),\n [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],\n )\n\n return (\n \n \n \n {children}\n \n \n \n )\n})\nSidebarProvider.displayName = \"SidebarProvider\"\n\nconst Sidebar = React.forwardRef>(\n ({ className, ...props }, ref) => (\n \n ),\n)\nSidebar.displayName = \"Sidebar\"\n\nconst SidebarTrigger = React.forwardRef, React.ComponentProps>(\n ({ className, onClick, ...props }, ref) => {\n const { toggleSidebar } = useSidebar()\n\n return (\n {\n onClick?.(event)\n toggleSidebar()\n }}\n {...props}\n >\n \n Toggle Sidebar\n \n )\n },\n)\nSidebarTrigger.displayName = \"SidebarTrigger\"\n\nconst SidebarRail = React.forwardRef>(\n ({ className, ...props }, ref) => {\n const { toggleSidebar } = useSidebar()\n\n return (\n