learning_ai_common_plat/packages/ui/src/components/Modal.tsx

65 lines
1.8 KiB
TypeScript

'use client';
import * as React from 'react';
import * as Dialog from '@radix-ui/react-dialog';
import { clsx } from 'clsx';
import { X } from 'lucide-react';
export interface ModalProps {
open: boolean;
onOpenChange: (open: boolean) => void;
title: string;
description?: string;
size?: 'sm' | 'md' | 'lg' | 'full';
children: React.ReactNode;
}
const sizes: Record<string, string> = {
sm: 'max-w-sm',
md: 'max-w-lg',
lg: 'max-w-2xl',
full: 'max-w-[90vw]',
};
export function Modal({
open,
onOpenChange,
title,
description,
size = 'md',
children,
}: ModalProps) {
return (
<Dialog.Root open={open} onOpenChange={onOpenChange}>
<Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 z-[9998] bg-black/60 backdrop-blur-sm" />
<Dialog.Content
className={clsx(
'fixed left-1/2 top-1/2 z-[9999] -translate-x-1/2 -translate-y-1/2',
'w-full rounded-xl border p-6 shadow-xl',
'bg-[var(--bl-bg-elevated,#12151c)] border-[var(--bl-border,#2a2a4a)] text-[var(--bl-text-primary,#fff)]',
'focus:outline-none',
sizes[size]
)}
>
<Dialog.Title className="text-lg font-semibold">{title}</Dialog.Title>
{description && (
<Dialog.Description className="mt-1 text-sm text-[var(--bl-text-secondary,#a0a0b0)]">
{description}
</Dialog.Description>
)}
<div className="mt-4">{children}</div>
<Dialog.Close asChild>
<button
className="absolute right-4 top-4 text-[var(--bl-text-tertiary,#666)] hover:text-[var(--bl-text-primary,#fff)]"
aria-label="Close dialog"
>
<X className="h-4 w-4" />
</button>
</Dialog.Close>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}