diff --git a/src/components/ui/sidebar.tsx b/src/components/ui/sidebar.tsx deleted file mode 100644 index 9d3c184..0000000 --- a/src/components/ui/sidebar.tsx +++ /dev/null @@ -1,722 +0,0 @@ -"use client" - -import { CSSProperties, ComponentProps, createContext, useCallback, useContext, useEffect, useMemo, useState } from "react" -import { Slot } from "@radix-ui/react-slot" -import { VariantProps, cva } from "class-variance-authority" -import PanelLeftIcon from "lucide-react/dist/esm/icons/panel-left" - -import { useIsMobile } from "@/hooks/use-mobile" -import { useThemeConfig } from "@/hooks/use-theme-config" -import { cn } from "@/lib/utils" -import { Button } from "@/components/ui/button" -import { Input } from "@/components/ui/input" -import { Separator } from "@/components/ui/separator" -import { - Sheet, - SheetContent, - SheetDescription, - SheetHeader, - SheetTitle, -} from "@/components/ui/sheet" -import { Skeleton } from "@/components/ui/skeleton" -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip" - -const SIDEBAR_COOKIE_NAME = "sidebar_state" -const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7 -const SIDEBAR_KEYBOARD_SHORTCUT = "b" - -type SidebarContextProps = { - state: "expanded" | "collapsed" - open: boolean - setOpen: (open: boolean) => void - openMobile: boolean - setOpenMobile: (open: boolean) => void - isMobile: boolean - toggleSidebar: () => void -} - -const SidebarContext = createContext(null) - -function useSidebar() { - const context = 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 -}: ComponentProps<"div"> & { - defaultOpen?: boolean - open?: boolean - onOpenChange?: (open: boolean) => void -}) { - const isMobile = useIsMobile() - const { themeConfig } = useThemeConfig() - const [openMobile, setOpenMobile] = useState(false) - - const sidebarWidth = themeConfig.sidebar?.width || '16rem' - const sidebarWidthIcon = themeConfig.sidebar?.widthIcon || '3rem' - - const [_open, _setOpen] = useState(defaultOpen) - const open = openProp ?? _open - const setOpen = useCallback( - (value: boolean | ((value: boolean) => boolean)) => { - const openState = typeof value === "function" ? value(open) : value - if (setOpenProp) { - setOpenProp(openState) - } else { - _setOpen(openState) - } - - document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}` - }, - [setOpenProp, open] - ) - - const toggleSidebar = useCallback(() => { - return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open) - }, [isMobile, setOpen, setOpenMobile]) - - useEffect(() => { - const handleKeyDown = (event: KeyboardEvent) => { - if ( - event.key === SIDEBAR_KEYBOARD_SHORTCUT && - (event.metaKey || event.ctrlKey) - ) { - event.preventDefault() - toggleSidebar() - } - } - - window.addEventListener("keydown", handleKeyDown) - return () => window.removeEventListener("keydown", handleKeyDown) - }, [toggleSidebar]) - - const state = open ? "expanded" : "collapsed" - - const contextValue = 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 -}: ComponentProps<"div"> & { - side?: "left" | "right" - variant?: "sidebar" | "floating" | "inset" - collapsible?: "offcanvas" | "icon" | "none" -}) { - const { isMobile, state, openMobile, setOpenMobile } = useSidebar() - const { themeConfig } = useThemeConfig() - - const sidebarWidthMobile = themeConfig.sidebar?.widthMobile || '18rem' - - if (collapsible === "none") { - return ( -
- {children} -
- ) - } - - if (isMobile) { - return ( - - - - Sidebar - Displays the mobile sidebar. - -
{children}
-
-
- ) - } - - return ( -
-
- -
- ) -} - -function SidebarTrigger({ - className, - onClick, - ...props -}: ComponentProps) { - const { toggleSidebar } = useSidebar() - - return ( - - ) -} - -function SidebarRail({ className, ...props }: ComponentProps<"button">) { - const { toggleSidebar } = useSidebar() - - return ( - + ) +} + +export { SidebarTrigger } diff --git a/src/components/ui/sidebar/sidebar.tsx b/src/components/ui/sidebar/sidebar.tsx new file mode 100644 index 0000000..09dac72 --- /dev/null +++ b/src/components/ui/sidebar/sidebar.tsx @@ -0,0 +1,114 @@ +"use client" + +import { CSSProperties, ComponentProps } from "react" + +import sidebarConfig from "@/data/sidebar-config.json" +import { useThemeConfig } from "@/hooks/use-theme-config" +import { cn } from "@/lib/utils" +import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@/components/ui/sheet" +import { useSidebar } from "@/components/ui/sidebar/use-sidebar" + +function Sidebar({ + side = "left", + variant = "sidebar", + collapsible = "offcanvas", + className, + children, + ...props +}: ComponentProps<"div"> & { + side?: "left" | "right" + variant?: "sidebar" | "floating" | "inset" + collapsible?: "offcanvas" | "icon" | "none" +}) { + const { isMobile, state, openMobile, setOpenMobile } = useSidebar() + const { themeConfig } = useThemeConfig() + + const sidebarWidthMobile = themeConfig.sidebar?.widthMobile || "18rem" + + if (collapsible === "none") { + return ( +
+ {children} +
+ ) + } + + if (isMobile) { + return ( + + + + {sidebarConfig.labels.sidebarTitle} + {sidebarConfig.labels.sidebarDescription} + +
{children}
+
+
+ ) + } + + return ( +
+
+ +
+ ) +} + +export { Sidebar } diff --git a/src/components/ui/sidebar/use-sidebar.ts b/src/components/ui/sidebar/use-sidebar.ts new file mode 100644 index 0000000..334896f --- /dev/null +++ b/src/components/ui/sidebar/use-sidebar.ts @@ -0,0 +1,14 @@ +import { useContext } from "react" + +import { SidebarContext } from "@/components/ui/sidebar/sidebar-context" + +function useSidebar() { + const context = useContext(SidebarContext) + if (!context) { + throw new Error("useSidebar must be used within a SidebarProvider.") + } + + return context +} + +export { useSidebar } diff --git a/src/data/sidebar-config.json b/src/data/sidebar-config.json new file mode 100644 index 0000000..3a3e150 --- /dev/null +++ b/src/data/sidebar-config.json @@ -0,0 +1,12 @@ +{ + "cookie": { + "name": "sidebar_state", + "maxAgeSeconds": 604800 + }, + "keyboardShortcut": "b", + "labels": { + "toggleSidebar": "Toggle Sidebar", + "sidebarTitle": "Sidebar", + "sidebarDescription": "Displays the mobile sidebar." + } +}