185 lines
4.6 KiB
TypeScript
185 lines
4.6 KiB
TypeScript
"use client";
|
|
|
|
import type { ReactNode } from "react";
|
|
import { AlertTriangle, X } from "lucide-react";
|
|
|
|
type ConfirmActionDialogProps = {
|
|
open: boolean;
|
|
title: string;
|
|
description: string;
|
|
confirmLabel: string;
|
|
cancelLabel?: string;
|
|
tone?: "danger" | "warning" | "info";
|
|
note?: string;
|
|
icon?: ReactNode;
|
|
onClose: () => void;
|
|
onConfirm: () => void;
|
|
};
|
|
|
|
const toneStyles = {
|
|
danger: {
|
|
color: "#ef4444",
|
|
softBackground: "rgba(239,68,68,0.08)",
|
|
strongBackground: "rgba(239,68,68,0.12)",
|
|
border: "rgba(239,68,68,0.22)",
|
|
lightBorder: "rgba(239,68,68,0.18)",
|
|
},
|
|
warning: {
|
|
color: "#f59e0b",
|
|
softBackground: "rgba(245,158,11,0.08)",
|
|
strongBackground: "rgba(245,158,11,0.12)",
|
|
border: "rgba(245,158,11,0.22)",
|
|
lightBorder: "rgba(245,158,11,0.18)",
|
|
},
|
|
info: {
|
|
color: "#3b82f6",
|
|
softBackground: "rgba(59,130,246,0.08)",
|
|
strongBackground: "rgba(59,130,246,0.12)",
|
|
border: "rgba(59,130,246,0.22)",
|
|
lightBorder: "rgba(59,130,246,0.18)",
|
|
},
|
|
} as const;
|
|
|
|
export default function ConfirmActionDialog({
|
|
open,
|
|
title,
|
|
description,
|
|
confirmLabel,
|
|
cancelLabel = "Cancel",
|
|
tone = "danger",
|
|
note,
|
|
icon,
|
|
onClose,
|
|
onConfirm,
|
|
}: ConfirmActionDialogProps) {
|
|
if (!open) {
|
|
return null;
|
|
}
|
|
|
|
const palette = toneStyles[tone];
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
position: "fixed",
|
|
inset: 0,
|
|
background: "rgba(2, 6, 23, 0.68)",
|
|
backdropFilter: "blur(6px)",
|
|
zIndex: 2200,
|
|
display: "grid",
|
|
placeItems: "center",
|
|
padding: 20,
|
|
}}
|
|
onClick={onClose}
|
|
>
|
|
<div
|
|
className="modal-shell"
|
|
style={{
|
|
width: "min(100%, 520px)",
|
|
maxWidth: 520,
|
|
}}
|
|
onClick={(event) => event.stopPropagation()}
|
|
>
|
|
<button
|
|
type="button"
|
|
onClick={onClose}
|
|
className="modal-close"
|
|
aria-label="Close confirmation dialog"
|
|
>
|
|
<X size={22} />
|
|
</button>
|
|
<div
|
|
className="card"
|
|
style={{
|
|
padding: 0,
|
|
overflow: "hidden",
|
|
boxShadow: "0 28px 70px rgba(2, 6, 23, 0.46)",
|
|
}}
|
|
>
|
|
<div style={{ padding: 28, display: "grid", gap: 18 }}>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
gap: 12,
|
|
paddingRight: 28,
|
|
}}
|
|
>
|
|
<div style={{ display: "grid", gap: 8 }}>
|
|
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
|
|
<div
|
|
style={{
|
|
width: 34,
|
|
height: 34,
|
|
borderRadius: 10,
|
|
border: `1px solid ${palette.lightBorder}`,
|
|
background: palette.softBackground,
|
|
display: "grid",
|
|
placeItems: "center",
|
|
color: palette.color,
|
|
}}
|
|
>
|
|
{icon ?? <AlertTriangle size={16} />}
|
|
</div>
|
|
<strong style={{ color: "var(--text-primary)", fontSize: 18 }}>
|
|
{title}
|
|
</strong>
|
|
</div>
|
|
<p
|
|
style={{
|
|
color: "var(--text-muted)",
|
|
fontSize: 14,
|
|
lineHeight: 1.7,
|
|
maxWidth: 430,
|
|
}}
|
|
>
|
|
{description}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{note ? (
|
|
<div
|
|
style={{
|
|
borderRadius: 12,
|
|
border: `1px solid ${palette.lightBorder}`,
|
|
background: palette.softBackground,
|
|
padding: "14px 16px",
|
|
color: palette.color,
|
|
fontSize: 13,
|
|
lineHeight: 1.7,
|
|
}}
|
|
>
|
|
{note}
|
|
</div>
|
|
) : null}
|
|
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
gap: 10,
|
|
justifyContent: "flex-end",
|
|
}}
|
|
>
|
|
<button className="btn" onClick={onClose}>
|
|
{cancelLabel}
|
|
</button>
|
|
<button
|
|
className="btn"
|
|
onClick={onConfirm}
|
|
style={{
|
|
background: palette.strongBackground,
|
|
color: palette.color,
|
|
border: `1px solid ${palette.border}`,
|
|
}}
|
|
>
|
|
{icon ?? <AlertTriangle size={14} />}
|
|
{confirmLabel}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|