1.6 KB75 lines
Blame
1"use client";
2
3import { useRef, useEffect } from "react";
4
5export interface DialogProps {
6 open: boolean;
7 onClose: () => void;
8 title: string;
9 children: React.ReactNode;
10 actions?: React.ReactNode;
11 className?: string;
12}
13
14export function Dialog({
15 open,
16 onClose,
17 title,
18 children,
19 actions,
20 className = "",
21}: DialogProps) {
22 const ref = useRef<HTMLDialogElement>(null);
23
24 useEffect(() => {
25 const dialog = ref.current;
26 if (!dialog) return;
27
28 if (open && !dialog.open) {
29 dialog.showModal();
30 } else if (!open && dialog.open) {
31 dialog.close();
32 }
33 }, [open]);
34
35 return (
36 <dialog
37 ref={ref}
38 onClose={onClose}
39 onClick={(e) => {
40 if (e.target === ref.current) onClose();
41 }}
42 className={className}
43 style={{
44 backgroundColor: "var(--bg-card)",
45 border: "1px solid var(--border-subtle)",
46 color: "var(--text-primary)",
47 width: "100%",
48 maxWidth: "28rem",
49 margin: "auto",
50 boxShadow: "0 8px 30px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06)",
51 overflow: "hidden",
52 }}
53 >
54 <div
55 className="px-6 pt-6 pb-4"
56 style={{ borderBottom: "1px solid var(--border-subtle)" }}
57 >
58 <h2 className="text-lg">{title}</h2>
59 </div>
60 <div className="px-6 py-5">{children}</div>
61 {actions && (
62 <div
63 className="flex gap-3 px-6 py-4 justify-end"
64 style={{
65 borderTop: "1px solid var(--border-subtle)",
66 backgroundColor: "var(--bg-inset)",
67 }}
68 >
69 {actions}
70 </div>
71 )}
72 </dialog>
73 );
74}
75