Update modal components to start from top on mobile devices and center on larger screens, improving usability across screen sizes. Also refine transition handling in privacy popup for cleaner unmounting.
107 lines
3.8 KiB
TypeScript
107 lines
3.8 KiB
TypeScript
import { Fragment, KeyboardEvent } from 'react';
|
|
import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@headlessui/react';
|
|
|
|
interface ConfirmDialogProps {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
onConfirm: () => void;
|
|
title: string;
|
|
message: string;
|
|
confirmText?: string;
|
|
cancelText?: string;
|
|
isDangerous?: boolean;
|
|
}
|
|
|
|
export function ConfirmDialog({
|
|
isOpen,
|
|
onClose,
|
|
onConfirm,
|
|
title,
|
|
message,
|
|
confirmText = 'Confirm',
|
|
cancelText = 'Cancel',
|
|
isDangerous = false,
|
|
}: ConfirmDialogProps) {
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
if (e.key === 'Enter') {
|
|
e.preventDefault();
|
|
onConfirm();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Transition appear show={isOpen} as={Fragment}>
|
|
<Dialog
|
|
as="div"
|
|
role={undefined}
|
|
className="relative z-50"
|
|
onClose={onClose}
|
|
onKeyDown={handleKeyDown}
|
|
>
|
|
<TransitionChild
|
|
as={Fragment}
|
|
enter="ease-out duration-300"
|
|
enterFrom="opacity-0"
|
|
enterTo="opacity-100"
|
|
leave="ease-in duration-200"
|
|
leaveFrom="opacity-100"
|
|
leaveTo="opacity-0"
|
|
>
|
|
<div className="fixed inset-0 overlay-dim backdrop-blur-sm" />
|
|
</TransitionChild>
|
|
|
|
<div className="fixed inset-0 overflow-y-auto">
|
|
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
|
<TransitionChild
|
|
as={Fragment}
|
|
enter="ease-out duration-300"
|
|
enterFrom="opacity-0 scale-95"
|
|
enterTo="opacity-100 scale-100"
|
|
leave="ease-in duration-200"
|
|
leaveFrom="opacity-100 scale-100"
|
|
leaveTo="opacity-0 scale-95"
|
|
>
|
|
<DialogPanel role='dialog' className="w-full max-w-md transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition-all">
|
|
<DialogTitle
|
|
as="h3"
|
|
className="text-lg font-semibold leading-6 text-foreground"
|
|
>
|
|
{title}
|
|
</DialogTitle>
|
|
<div className="mt-2">
|
|
<p className="text-sm text-foreground/90">{message}</p>
|
|
</div>
|
|
|
|
<div className="mt-6 flex justify-end space-x-3">
|
|
<button
|
|
type="button"
|
|
className="inline-flex justify-center rounded-lg bg-background px-3 py-1.5 text-sm
|
|
font-medium text-foreground hover:bg-offbase focus:outline-none
|
|
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
|
transform transition-transform duration-200 ease-in-out hover:scale-[1.04] hover:text-accent"
|
|
onClick={onClose}
|
|
>
|
|
{cancelText}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className={`inline-flex justify-center rounded-lg px-3 py-1.5 text-sm
|
|
font-medium focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2
|
|
transform transition-transform duration-200 ease-in-out hover:scale-[1.04]
|
|
${isDangerous
|
|
? 'bg-accent text-background hover:bg-secondary-accent focus-visible:ring-accent'
|
|
: 'bg-accent text-background hover:bg-secondary-accent focus-visible:ring-accent'
|
|
}`}
|
|
onClick={onConfirm}
|
|
>
|
|
{confirmText}
|
|
</button>
|
|
</div>
|
|
</DialogPanel>
|
|
</TransitionChild>
|
|
</div>
|
|
</div>
|
|
</Dialog>
|
|
</Transition>
|
|
);
|
|
}
|