|
|
|
@@ -1,12 +1,9 @@
|
|
|
|
|
"use client"
|
|
|
|
|
|
|
|
|
|
import * as React from "react"
|
|
|
|
|
import { Slot } from "@radix-ui/react-slot"
|
|
|
|
|
import { cva, VariantProps } from "class-variance-authority"
|
|
|
|
|
import { cva, type VariantProps } from "class-variance-authority"
|
|
|
|
|
import { PanelLeftIcon } from "lucide-react"
|
|
|
|
|
|
|
|
|
|
import { useIsMobile } from "@/hooks/use-mobile"
|
|
|
|
|
import { cn } from "@/lib/utils"
|
|
|
|
|
import * as React from "react"
|
|
|
|
|
import { Button } from "@/components/ui/button"
|
|
|
|
|
import { Input } from "@/components/ui/input"
|
|
|
|
|
import { Separator } from "@/components/ui/separator"
|
|
|
|
@@ -24,6 +21,8 @@ import {
|
|
|
|
|
TooltipProvider,
|
|
|
|
|
TooltipTrigger,
|
|
|
|
|
} from "@/components/ui/tooltip"
|
|
|
|
|
import { useIsMobile } from "@/hooks/use-mobile"
|
|
|
|
|
import { cn } from "@/lib/utils"
|
|
|
|
|
|
|
|
|
|
const SIDEBAR_COOKIE_NAME = "sidebar_state"
|
|
|
|
|
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
|
|
|
|
@@ -85,12 +84,14 @@ function SidebarProvider({
|
|
|
|
|
// This sets the cookie to keep the sidebar state.
|
|
|
|
|
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
|
|
|
|
|
},
|
|
|
|
|
[setOpenProp, open]
|
|
|
|
|
[setOpenProp, open],
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Helper to toggle the sidebar.
|
|
|
|
|
const toggleSidebar = React.useCallback(() => {
|
|
|
|
|
return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)
|
|
|
|
|
return isMobile
|
|
|
|
|
? setOpenMobile((open) => !open)
|
|
|
|
|
: setOpen((open) => !open)
|
|
|
|
|
}, [isMobile, setOpen, setOpenMobile])
|
|
|
|
|
|
|
|
|
|
// Adds a keyboard shortcut to toggle the sidebar.
|
|
|
|
@@ -123,7 +124,15 @@ function SidebarProvider({
|
|
|
|
|
setOpenMobile,
|
|
|
|
|
toggleSidebar,
|
|
|
|
|
}),
|
|
|
|
|
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
|
|
|
|
|
[
|
|
|
|
|
state,
|
|
|
|
|
open,
|
|
|
|
|
setOpen,
|
|
|
|
|
isMobile,
|
|
|
|
|
openMobile,
|
|
|
|
|
setOpenMobile,
|
|
|
|
|
toggleSidebar,
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
@@ -140,7 +149,7 @@ function SidebarProvider({
|
|
|
|
|
}
|
|
|
|
|
className={cn(
|
|
|
|
|
"group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",
|
|
|
|
|
className
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
>
|
|
|
|
@@ -171,7 +180,7 @@ function Sidebar({
|
|
|
|
|
data-slot="sidebar"
|
|
|
|
|
className={cn(
|
|
|
|
|
"bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",
|
|
|
|
|
className
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
>
|
|
|
|
@@ -197,9 +206,13 @@ function Sidebar({
|
|
|
|
|
>
|
|
|
|
|
<SheetHeader className="sr-only">
|
|
|
|
|
<SheetTitle>Sidebar</SheetTitle>
|
|
|
|
|
<SheetDescription>Displays the mobile sidebar.</SheetDescription>
|
|
|
|
|
<SheetDescription>
|
|
|
|
|
Displays the mobile sidebar.
|
|
|
|
|
</SheetDescription>
|
|
|
|
|
</SheetHeader>
|
|
|
|
|
<div className="flex h-full w-full flex-col">{children}</div>
|
|
|
|
|
<div className="flex h-full w-full flex-col">
|
|
|
|
|
{children}
|
|
|
|
|
</div>
|
|
|
|
|
</SheetContent>
|
|
|
|
|
</Sheet>
|
|
|
|
|
)
|
|
|
|
@@ -223,7 +236,7 @@ function Sidebar({
|
|
|
|
|
"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)"
|
|
|
|
|
: "group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<div
|
|
|
|
@@ -237,7 +250,7 @@ function Sidebar({
|
|
|
|
|
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=left]:border-r group-data-[side=right]:border-l",
|
|
|
|
|
className
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
>
|
|
|
|
@@ -297,7 +310,7 @@ function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
|
|
|
|
|
"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
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
/>
|
|
|
|
@@ -311,7 +324,7 @@ function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
|
|
|
|
|
className={cn(
|
|
|
|
|
"bg-background 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
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
/>
|
|
|
|
@@ -375,7 +388,7 @@ function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
|
|
data-sidebar="content"
|
|
|
|
|
className={cn(
|
|
|
|
|
"flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
|
|
|
|
|
className
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
/>
|
|
|
|
@@ -387,7 +400,10 @@ function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
|
|
<div
|
|
|
|
|
data-slot="sidebar-group"
|
|
|
|
|
data-sidebar="group"
|
|
|
|
|
className={cn("relative flex w-full min-w-0 flex-col p-2", className)}
|
|
|
|
|
className={cn(
|
|
|
|
|
"relative flex w-full min-w-0 flex-col p-2",
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
/>
|
|
|
|
|
)
|
|
|
|
@@ -407,7 +423,7 @@ function SidebarGroupLabel({
|
|
|
|
|
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
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
/>
|
|
|
|
@@ -430,7 +446,7 @@ function SidebarGroupAction({
|
|
|
|
|
// Increases the hit area of the button on mobile.
|
|
|
|
|
"after:absolute after:-inset-2 md:after:hidden",
|
|
|
|
|
"group-data-[collapsible=icon]:hidden",
|
|
|
|
|
className
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
/>
|
|
|
|
@@ -478,7 +494,8 @@ const sidebarMenuButtonVariants = cva(
|
|
|
|
|
{
|
|
|
|
|
variants: {
|
|
|
|
|
variant: {
|
|
|
|
|
default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
|
|
|
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))]",
|
|
|
|
|
},
|
|
|
|
@@ -492,7 +509,7 @@ const sidebarMenuButtonVariants = cva(
|
|
|
|
|
variant: "default",
|
|
|
|
|
size: "default",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
function SidebarMenuButton({
|
|
|
|
@@ -517,7 +534,10 @@ function SidebarMenuButton({
|
|
|
|
|
data-sidebar="menu-button"
|
|
|
|
|
data-size={size}
|
|
|
|
|
data-active={isActive}
|
|
|
|
|
className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
|
|
|
|
|
className={cn(
|
|
|
|
|
sidebarMenuButtonVariants({ variant, size }),
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
/>
|
|
|
|
|
)
|
|
|
|
@@ -570,7 +590,7 @@ function SidebarMenuAction({
|
|
|
|
|
"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
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
/>
|
|
|
|
@@ -592,7 +612,7 @@ function SidebarMenuBadge({
|
|
|
|
|
"peer-data-[size=default]/menu-button:top-1.5",
|
|
|
|
|
"peer-data-[size=lg]/menu-button:top-2.5",
|
|
|
|
|
"group-data-[collapsible=icon]:hidden",
|
|
|
|
|
className
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
/>
|
|
|
|
@@ -615,7 +635,10 @@ function SidebarMenuSkeleton({
|
|
|
|
|
<div
|
|
|
|
|
data-slot="sidebar-menu-skeleton"
|
|
|
|
|
data-sidebar="menu-skeleton"
|
|
|
|
|
className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)}
|
|
|
|
|
className={cn(
|
|
|
|
|
"flex h-8 items-center gap-2 rounded-md px-2",
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
>
|
|
|
|
|
{showIcon && (
|
|
|
|
@@ -645,7 +668,7 @@ function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
|
|
|
|
|
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
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
/>
|
|
|
|
@@ -691,7 +714,7 @@ function SidebarMenuSubButton({
|
|
|
|
|
size === "sm" && "text-xs",
|
|
|
|
|
size === "md" && "text-sm",
|
|
|
|
|
"group-data-[collapsible=icon]:hidden",
|
|
|
|
|
className
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
{...props}
|
|
|
|
|
/>
|
|
|
|
|