Files
KVideo/components/ui/ConfirmDialog.tsx
T
kuekhaoyangandClaude Opus 4.6 df137c97f3 feat: upgrade Liquid Glass design system to full spec (v4.6.0)
- Upgrade CSS variables with proper glass transparency, fixed gradient
  backgrounds, cubic-bezier(0.2, 0.8, 0.2, 1) fluid transitions, and
  enhanced shadow/border values matching the Liquid Glass touchstone
- Add full backdrop-filter: blur(25px) saturate(180%) to glass-card,
  glass-input, glass-popover, and glass-backdrop CSS classes
- Add lensing inner-glow hover effects and toast-in animation
- Update all UI components (Button, Card, Input, Badge, Switch,
  SegmentedControl, ConfirmDialog, ModalBackdrop, ModalHeader,
  BackToTop, Navbar) for strict Liquid Glass compliance
- Enforce rounded-2xl / rounded-full consistency across all components
- Bump version to 4.6.0, update @vercel/analytics to ^2.0.1

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-15 15:47:16 +08:00

115 lines
2.9 KiB
TypeScript

'use client';
import { useEffect, useRef } from 'react';
import { Button } from './Button';
import { Card } from './Card';
interface ConfirmDialogProps {
isOpen: boolean;
title: string;
message: string;
onConfirm: () => void;
onCancel: () => void;
confirmText?: string;
cancelText?: string;
variant?: 'danger' | 'warning' | 'info';
dangerous?: boolean;
}
export function ConfirmDialog({
isOpen,
title,
message,
onConfirm,
onCancel,
confirmText = '确认',
cancelText = '取消',
variant = 'warning',
dangerous = false,
}: ConfirmDialogProps) {
const cancelButtonRef = useRef<HTMLButtonElement>(null);
useEffect(() => {
if (isOpen) {
cancelButtonRef.current?.focus();
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = '';
}
return () => { document.body.style.overflow = ''; };
}, [isOpen]);
useEffect(() => {
if (!isOpen) return;
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
e.preventDefault();
onCancel();
}
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
}, [isOpen, onCancel]);
if (!isOpen) return null;
const variantStyles = {
danger: 'bg-red-500 hover:bg-red-600',
warning: 'bg-[var(--accent-color)] hover:brightness-110',
info: 'bg-blue-500 hover:bg-blue-600',
};
const finalVariant = dangerous ? 'danger' : variant;
return (
<>
{/* Backdrop */}
<div
className="fixed inset-0 z-[9998] bg-black/30 backdrop-blur-[8px] [-webkit-backdrop-filter:blur(8px)] animate-fade-in"
onClick={onCancel}
aria-hidden="true"
/>
{/* Dialog */}
<div
role="alertdialog"
aria-modal="true"
aria-labelledby="dialog-title"
aria-describedby="dialog-description"
className="fixed top-1/2 left-1/2 z-[9999] w-[90%] max-w-md -translate-x-1/2 -translate-y-1/2 animate-scale-in"
>
<Card hover={false} className="p-6">
<h2
id="dialog-title"
className="text-xl font-semibold text-[var(--text-color)] mb-3"
>
{title}
</h2>
<p
id="dialog-description"
className="text-[var(--text-color-secondary)] mb-6 leading-relaxed"
>
{message}
</p>
<div className="flex gap-3 justify-end">
<Button
ref={cancelButtonRef}
variant="secondary"
onClick={onCancel}
className="min-w-[100px]"
>
{cancelText}
</Button>
<Button
onClick={onConfirm}
className={`min-w-[100px] ${variantStyles[finalVariant]}`}
>
{confirmText}
</Button>
</div>
</Card>
</div>
</>
);
}