veza/apps/web/src/components/ui/dialog/Dialog.tsx
senke 8a3da49fbd style(ui): elevate Dialog to SaaS Premium
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-07 15:08:52 +01:00

103 lines
2.2 KiB
TypeScript

import { Modal } from '../modal';
import { Button } from '../button';
import { cn } from '@/lib/utils';
import { AlertCircle, Info } from 'lucide-react';
import type { DialogProps, DialogVariant } from './types';
const variantIcons: Record<
DialogVariant,
typeof AlertCircle | typeof Info | undefined
> = {
alert: AlertCircle,
confirm: AlertCircle,
info: Info,
default: undefined,
};
const variantStyles: Record<DialogVariant, string> = {
alert: 'text-destructive',
confirm: 'text-primary',
info: 'text-muted-foreground',
default: '',
};
export function Dialog({
open,
onClose,
onOpenChange,
title,
children,
footer,
variant = 'default',
onConfirm,
onCancel,
confirmLabel = 'Confirm',
cancelLabel = 'Cancel',
showCancel = true,
size = 'md',
}: DialogProps) {
const handleClose = () => {
if (onOpenChange) {
onOpenChange(false);
} else if (onClose) {
onClose();
}
};
const handleConfirm = async () => {
if (onConfirm) {
await onConfirm();
}
handleClose();
};
const handleCancel = () => {
if (onCancel) {
onCancel();
}
handleClose();
};
const IconComponent = variantIcons[variant];
const iconStyle = variantStyles[variant];
return (
<Modal
open={open}
onClose={handleClose}
size={size}
closeOnOverlayClick={variant === 'default'}
title={title}
footer={
footer || onConfirm || onCancel ? (
footer ? (
footer
) : (
<div className="flex justify-end gap-2">
{showCancel && (
<Button variant="outline" onClick={handleCancel}>
{cancelLabel}
</Button>
)}
{onConfirm && (
<Button
variant={variant === 'alert' ? 'destructive' : 'default'}
onClick={handleConfirm}
>
{confirmLabel}
</Button>
)}
</div>
)
) : undefined
}
>
{title && IconComponent && (
<div className="flex items-center gap-4 mb-4">
<IconComponent className={cn('h-5 w-5', iconStyle)} />
</div>
)}
{children}
</Modal>
);
}