testes/src_2/components/shared/Modal.jsx

71 lines
2.3 KiB
JavaScript

import React, { useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { X } from 'lucide-react';
import { Button } from '@/components/ui/button';
const Modal = ({ isOpen, onClose, title, children }) => {
// Close on ESC key
useEffect(() => {
const handleEsc = (e) => {
if (e.key === 'Escape') onClose();
};
window.addEventListener('keydown', handleEsc);
return () => window.removeEventListener('keydown', handleEsc);
}, [onClose]);
// Prevent scroll when open
useEffect(() => {
if (isOpen) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = 'unset';
}
}, [isOpen]);
return (
<AnimatePresence>
{isOpen && (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
{/* Backdrop */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
className="absolute inset-0 bg-slate-950/40 backdrop-blur-sm"
/>
{/* Modal Content */}
<motion.div
initial={{ opacity: 0, scale: 0.95, y: 30 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: 30 }}
transition={{ type: 'spring', duration: 0.6, bounce: 0.3 }}
className="relative w-full max-w-md bg-[#1e293b] rounded-2xl shadow-[0_32px_64px_-12px_rgba(0,0,0,0.6)] border border-slate-800 overflow-hidden"
>
{/* Header */}
<div className="p-6 pb-4 border-b border-slate-800 flex justify-between items-center bg-slate-900/40">
<h3 className="text-sm font-black text-white uppercase tracking-[0.2em]">{title}</h3>
<Button
variant="ghost"
size="icon"
onClick={onClose}
className="rounded-xl h-8 w-8 hover:bg-slate-800 text-slate-500 hover:text-white transition-all shadow-inner border border-transparent hover:border-slate-700"
>
<X className="w-4 h-4" />
</Button>
</div>
{/* Body */}
<div className="p-8">
{children}
</div>
</motion.div>
</div>
)}
</AnimatePresence>
);
};
export default Modal;