Spaces:
Sleeping
Sleeping
| "use client"; | |
| import { useEffect } from "react"; | |
| import { cn } from "@/shared/utils/cn"; | |
| export default function Drawer({ | |
| isOpen, | |
| onClose, | |
| title, | |
| children, | |
| width = "md", | |
| className | |
| }) { | |
| const widths = { | |
| sm: "w-[400px]", | |
| md: "w-[500px]", | |
| lg: "w-[600px]", | |
| xl: "w-[800px]", | |
| full: "w-full", | |
| }; | |
| useEffect(() => { | |
| if (isOpen) { | |
| document.body.style.overflow = "hidden"; | |
| } else { | |
| document.body.style.overflow = ""; | |
| } | |
| return () => { document.body.style.overflow = ""; }; | |
| }, [isOpen]); | |
| useEffect(() => { | |
| const handleEscape = (e) => { | |
| if (e.key === "Escape" && isOpen) onClose(); | |
| }; | |
| document.addEventListener("keydown", handleEscape); | |
| return () => document.removeEventListener("keydown", handleEscape); | |
| }, [isOpen, onClose]); | |
| if (!isOpen) return null; | |
| return ( | |
| <div className="fixed inset-0 z-50"> | |
| {/* Overlay */} | |
| <div | |
| className="absolute inset-0 bg-black/50 backdrop-blur-[2px] fade-in cursor-pointer" | |
| onClick={onClose} | |
| aria-hidden="true" | |
| /> | |
| {/* Drawer panel */} | |
| <div className={cn( | |
| "absolute right-0 top-0 h-full bg-surface flex flex-col", | |
| "shadow-[var(--shadow-elev)]", | |
| "slide-in-right", | |
| "border-l border-border-subtle", | |
| widths[width] || widths.md, | |
| className | |
| )}> | |
| {/* Header */} | |
| <div className="flex items-center justify-between p-6 border-b border-border-subtle flex-shrink-0"> | |
| <div className="flex items-center gap-3"> | |
| {title && ( | |
| <h2 className="text-lg font-semibold text-text-main">{title}</h2> | |
| )} | |
| </div> | |
| <button | |
| type="button" | |
| onClick={onClose} | |
| className="p-1.5 rounded-[10px] text-text-muted hover:bg-surface-2 hover:text-text-main transition-colors" | |
| > | |
| <span className="material-symbols-outlined text-[20px]">close</span> | |
| </button> | |
| </div> | |
| {/* Body */} | |
| <div className="flex-1 overflow-y-auto p-6 custom-scrollbar"> | |
| {children} | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |