fix: confirm dialog is now a compact popup, not full-screen overlay
- Removed full-screen overlay backdrop (bg-black/95 + backdrop-blur) - Dialog is centered via fixed left-1/2 top-1/2 -translate - Compact design: max-w-sm, smaller text, smaller buttons - Uses admin theme vars (admin-surface, admin-border, admin-text) - Smooth scale+fade animation without overlay
This commit is contained in:
1 parent
93601e58e0
commit
844add04ef
1 file changed
+54
-78
@@ -5,7 +5,6 @@ import { AnimatePresence, motion } from "motion/react";
|
|||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { modalContentVariants, modalOverlayVariants } from "@/lib/motion";
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export type ConfirmDialogProps = {
|
export type ConfirmDialogProps = {
|
||||||
@@ -20,10 +19,6 @@ export type ConfirmDialogProps = {
|
|||||||
onConfirm: () => void | Promise<void>;
|
onConfirm: () => void | Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Portal-based confirm modal (not Dialog.Root) so it can safely stack
|
|
||||||
* above Visual Manager / other Base UI dialogs without nested-root bugs.
|
|
||||||
*/
|
|
||||||
export function ConfirmDialog({
|
export function ConfirmDialog({
|
||||||
open,
|
open,
|
||||||
onOpenChange,
|
onOpenChange,
|
||||||
@@ -62,85 +57,66 @@ export function ConfirmDialog({
|
|||||||
|
|
||||||
if (!mounted) return null;
|
if (!mounted) return null;
|
||||||
|
|
||||||
const isOpen = open;
|
|
||||||
|
|
||||||
return createPortal(
|
return createPortal(
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{isOpen ? (
|
{open ? (
|
||||||
<motion.div
|
<motion.div
|
||||||
key="confirm-overlay"
|
key="confirm-popup"
|
||||||
className="fixed inset-0 z-[200] flex items-center justify-center p-4"
|
role="alertdialog"
|
||||||
variants={modalOverlayVariants}
|
aria-modal="true"
|
||||||
initial="hidden"
|
aria-labelledby="confirm-dialog-title"
|
||||||
animate="visible"
|
aria-describedby="confirm-dialog-desc"
|
||||||
exit="exit"
|
className="fixed left-1/2 top-1/2 z-[200] w-full max-w-sm -translate-x-1/2 -translate-y-1/2 rounded-lg border border-[var(--admin-border)] bg-[var(--admin-surface)] p-5 shadow-2xl"
|
||||||
|
initial={{ opacity: 0, scale: 0.95, y: -4 }}
|
||||||
|
animate={{ opacity: 1, scale: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, scale: 0.95, y: -4 }}
|
||||||
|
transition={{ duration: 0.15, ease: "easeOut" }}
|
||||||
>
|
>
|
||||||
<button
|
<div className="flex flex-col gap-2 text-left">
|
||||||
type="button"
|
<div className="flex items-center gap-2.5">
|
||||||
aria-label="Dismiss"
|
{variant === "danger" && (
|
||||||
className="absolute inset-0 bg-black/95"
|
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[var(--admin-error)]/15">
|
||||||
disabled={isLoading}
|
<AlertTriangle className="h-4 w-4 text-[var(--admin-error)]" />
|
||||||
onClick={() => {
|
</div>
|
||||||
if (!isLoading) onOpenChange(false);
|
)}
|
||||||
}}
|
<h2
|
||||||
/>
|
id="confirm-dialog-title"
|
||||||
<motion.div
|
className="text-sm font-semibold text-[var(--admin-text)]"
|
||||||
key="confirm-content"
|
|
||||||
role="alertdialog"
|
|
||||||
aria-modal="true"
|
|
||||||
aria-labelledby="confirm-dialog-title"
|
|
||||||
aria-describedby="confirm-dialog-desc"
|
|
||||||
className="relative z-10 w-full max-w-md rounded-xl border-2 border-primary/40 bg-surface p-6 text-card-foreground shadow-[0_0_60px_-10px_rgba(245,158,11,0.3)]"
|
|
||||||
variants={modalContentVariants}
|
|
||||||
initial="hidden"
|
|
||||||
animate="visible"
|
|
||||||
exit="exit"
|
|
||||||
>
|
|
||||||
<div className="flex flex-col gap-2 text-left">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
{variant === "danger" && (
|
|
||||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-destructive/15">
|
|
||||||
<AlertTriangle className="h-5 w-5 text-destructive" />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<h2
|
|
||||||
id="confirm-dialog-title"
|
|
||||||
className="text-lg font-semibold leading-none"
|
|
||||||
>
|
|
||||||
{title}
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<p
|
|
||||||
id="confirm-dialog-desc"
|
|
||||||
className="text-sm text-muted-foreground"
|
|
||||||
>
|
>
|
||||||
{description}
|
{title}
|
||||||
</p>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-6 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
|
<p
|
||||||
<Button
|
id="confirm-dialog-desc"
|
||||||
type="button"
|
className="text-xs text-[var(--admin-text-muted)]"
|
||||||
variant="outline"
|
>
|
||||||
disabled={isLoading}
|
{description}
|
||||||
onClick={() => onOpenChange(false)}
|
</p>
|
||||||
>
|
</div>
|
||||||
{cancelLabel}
|
<div className="mt-4 flex justify-end gap-2">
|
||||||
</Button>
|
<Button
|
||||||
<Button
|
type="button"
|
||||||
type="button"
|
variant="outline"
|
||||||
variant={variant === "danger" ? "destructive" : "default"}
|
size="sm"
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
onClick={handleConfirm}
|
onClick={() => onOpenChange(false)}
|
||||||
className={cn(
|
>
|
||||||
variant === "danger" &&
|
{cancelLabel}
|
||||||
"bg-destructive text-destructive-foreground",
|
</Button>
|
||||||
)}
|
<Button
|
||||||
autoFocus
|
type="button"
|
||||||
>
|
variant={variant === "danger" ? "destructive" : "default"}
|
||||||
{confirmLabel}
|
size="sm"
|
||||||
</Button>
|
disabled={isLoading}
|
||||||
</div>
|
onClick={handleConfirm}
|
||||||
</motion.div>
|
className={cn(
|
||||||
|
variant === "danger" && "bg-[var(--admin-error)] text-white",
|
||||||
|
)}
|
||||||
|
autoFocus
|
||||||
|
>
|
||||||
|
{confirmLabel}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
) : null}
|
) : null}
|
||||||
</AnimatePresence>,
|
</AnimatePresence>,
|
||||||
|
|||||||
Reference in new issue
Block a user