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:
openhands committed 2026-09-01 19:13:15 +02:00
1 parent 93601e58e0
commit 844add04ef
1 file changed
+54 -78
+54 -78
View File
@@ -5,7 +5,6 @@ import { AnimatePresence, motion } from "motion/react";
import { useCallback, useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { Button } from "@/components/ui/button";
import { modalContentVariants, modalOverlayVariants } from "@/lib/motion";
import { cn } from "@/lib/utils";
export type ConfirmDialogProps = {
@@ -20,10 +19,6 @@ export type ConfirmDialogProps = {
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({
open,
onOpenChange,
@@ -62,85 +57,66 @@ export function ConfirmDialog({
if (!mounted) return null;
const isOpen = open;
return createPortal(
<AnimatePresence>
{isOpen ? (
{open ? (
<motion.div
key="confirm-overlay"
className="fixed inset-0 z-[200] flex items-center justify-center p-4"
variants={modalOverlayVariants}
initial="hidden"
animate="visible"
exit="exit"
key="confirm-popup"
role="alertdialog"
aria-modal="true"
aria-labelledby="confirm-dialog-title"
aria-describedby="confirm-dialog-desc"
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
type="button"
aria-label="Dismiss"
className="absolute inset-0 bg-black/95"
disabled={isLoading}
onClick={() => {
if (!isLoading) onOpenChange(false);
}}
/>
<motion.div
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"
<div className="flex flex-col gap-2 text-left">
<div className="flex items-center gap-2.5">
{variant === "danger" && (
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[var(--admin-error)]/15">
<AlertTriangle className="h-4 w-4 text-[var(--admin-error)]" />
</div>
)}
<h2
id="confirm-dialog-title"
className="text-sm font-semibold text-[var(--admin-text)]"
>
{description}
</p>
{title}
</h2>
</div>
<div className="mt-6 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
<Button
type="button"
variant="outline"
disabled={isLoading}
onClick={() => onOpenChange(false)}
>
{cancelLabel}
</Button>
<Button
type="button"
variant={variant === "danger" ? "destructive" : "default"}
disabled={isLoading}
onClick={handleConfirm}
className={cn(
variant === "danger" &&
"bg-destructive text-destructive-foreground",
)}
autoFocus
>
{confirmLabel}
</Button>
</div>
</motion.div>
<p
id="confirm-dialog-desc"
className="text-xs text-[var(--admin-text-muted)]"
>
{description}
</p>
</div>
<div className="mt-4 flex justify-end gap-2">
<Button
type="button"
variant="outline"
size="sm"
disabled={isLoading}
onClick={() => onOpenChange(false)}
>
{cancelLabel}
</Button>
<Button
type="button"
variant={variant === "danger" ? "destructive" : "default"}
size="sm"
disabled={isLoading}
onClick={handleConfirm}
className={cn(
variant === "danger" && "bg-[var(--admin-error)] text-white",
)}
autoFocus
>
{confirmLabel}
</Button>
</div>
</motion.div>
) : null}
</AnimatePresence>,