59 أسطر
1.6 KiB
TypeScript
59 أسطر
1.6 KiB
TypeScript
"use client";
|
|
|
|
import type { ReactNode } from "react";
|
|
import { X } from "lucide-react";
|
|
|
|
import { cn } from "@/lib/utils";
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
type DrawerProps = {
|
|
open: boolean;
|
|
onClose: () => void;
|
|
title: string;
|
|
description?: string;
|
|
children: ReactNode;
|
|
side?: "left" | "right";
|
|
widthClassName?: string;
|
|
};
|
|
|
|
export function Drawer({
|
|
open,
|
|
onClose,
|
|
title,
|
|
description,
|
|
children,
|
|
side = "left",
|
|
widthClassName,
|
|
}: DrawerProps) {
|
|
return (
|
|
<>
|
|
<div
|
|
className={cn(
|
|
"fixed inset-0 z-40 bg-black/50 backdrop-blur-sm transition",
|
|
open ? "opacity-100" : "pointer-events-none opacity-0",
|
|
)}
|
|
onClick={onClose}
|
|
/>
|
|
<aside
|
|
className={cn(
|
|
"fixed bottom-0 top-0 z-50 w-[96vw] max-w-md border border-border bg-card p-5 shadow-glow transition",
|
|
widthClassName,
|
|
side === "left" ? "left-0" : "right-0",
|
|
open ? "translate-x-0" : side === "left" ? "-translate-x-full" : "translate-x-full",
|
|
)}
|
|
>
|
|
<div className="mb-5 flex items-start justify-between">
|
|
<div className="space-y-1">
|
|
<h3 className="font-heading text-lg font-bold">{title}</h3>
|
|
{description ? <p className="text-sm text-muted-foreground">{description}</p> : null}
|
|
</div>
|
|
<Button variant="ghost" size="icon" onClick={onClose}>
|
|
<X className="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
<div className="h-[calc(100%-72px)] overflow-y-auto">{children}</div>
|
|
</aside>
|
|
</>
|
|
);
|
|
}
|