Files
wzdj/app/admin/screen/_components/ui/sidebar.tsx

170 lines
5.3 KiB
TypeScript

"use client"
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const sidebarVariants = cva("flex h-full w-64 flex-col border-r bg-background", {
variants: {
variant: {
default: "border-border",
ghost: "border-transparent",
},
},
defaultVariants: {
variant: "default",
},
})
interface SidebarContextProps {
open: boolean
setOpen: (open: boolean) => void
}
const SidebarContext = React.createContext<SidebarContextProps | undefined>(undefined)
function useSidebar() {
const context = React.useContext(SidebarContext)
if (!context) {
throw new Error("useSidebar must be used within a SidebarProvider")
}
return context
}
interface SidebarProviderProps {
children: React.ReactNode
defaultOpen?: boolean
open?: boolean
onOpenChange?: (open: boolean) => void
}
const SidebarProvider = React.forwardRef<HTMLDivElement, SidebarProviderProps>(
({ children, defaultOpen = true, open: controlledOpen, onOpenChange, ...props }, ref) => {
const [internalOpen, setInternalOpen] = React.useState(defaultOpen)
const open = controlledOpen !== undefined ? controlledOpen : internalOpen
const setOpen = React.useCallback(
(newOpen: boolean) => {
if (controlledOpen === undefined) {
setInternalOpen(newOpen)
}
onOpenChange?.(newOpen)
},
[controlledOpen, onOpenChange],
)
return (
<SidebarContext.Provider value={{ open, setOpen }}>
<div ref={ref} {...props}>
{children}
</div>
</SidebarContext.Provider>
)
},
)
SidebarProvider.displayName = "SidebarProvider"
interface SidebarProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof sidebarVariants> {
asChild?: boolean
}
const Sidebar = React.forwardRef<HTMLDivElement, SidebarProps>(
({ className, variant, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "div"
return <Comp className={cn(sidebarVariants({ variant, className }))} ref={ref} {...props} />
},
)
Sidebar.displayName = "Sidebar"
const SidebarHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex items-center px-4 py-2", className)} {...props} />
),
)
SidebarHeader.displayName = "SidebarHeader"
const SidebarContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => <div ref={ref} className={cn("flex-1 overflow-auto py-2", className)} {...props} />,
)
SidebarContent.displayName = "SidebarContent"
const SidebarFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => <div ref={ref} className={cn("mt-auto px-4 py-2", className)} {...props} />,
)
SidebarFooter.displayName = "SidebarFooter"
const SidebarMenu = React.forwardRef<HTMLUListElement, React.HTMLAttributes<HTMLUListElement>>(
({ className, ...props }, ref) => <ul ref={ref} className={cn("space-y-1 px-2", className)} {...props} />,
)
SidebarMenu.displayName = "SidebarMenu"
const SidebarMenuItem = React.forwardRef<HTMLLIElement, React.HTMLAttributes<HTMLLIElement>>(
({ className, ...props }, ref) => <li ref={ref} className={cn("", className)} {...props} />,
)
SidebarMenuItem.displayName = "SidebarMenuItem"
interface SidebarMenuButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
asChild?: boolean
isActive?: boolean
}
const SidebarMenuButton = React.forwardRef<HTMLButtonElement, SidebarMenuButtonProps>(
({ className, asChild = false, isActive = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(
"flex w-full items-center rounded-md px-2 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50",
isActive && "bg-accent text-accent-foreground",
className,
)}
ref={ref}
{...props}
/>
)
},
)
SidebarMenuButton.displayName = "SidebarMenuButton"
const SidebarInset = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => <div ref={ref} className={cn("flex-1", className)} {...props} />,
)
SidebarInset.displayName = "SidebarInset"
const SidebarTrigger = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(
({ className, children, ...props }, ref) => {
const { setOpen, open } = useSidebar()
return (
<button
ref={ref}
className={cn(
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-9 w-9",
className,
)}
onClick={() => setOpen(!open)}
{...props}
>
{children}
</button>
)
},
)
SidebarTrigger.displayName = "SidebarTrigger"
export {
Sidebar,
SidebarProvider,
SidebarHeader,
SidebarContent,
SidebarFooter,
SidebarMenu,
SidebarMenuItem,
SidebarMenuButton,
SidebarInset,
SidebarTrigger,
useSidebar,
}