71 lines
1.6 KiB
TypeScript
71 lines
1.6 KiB
TypeScript
"use client";
|
|
|
|
import { ReactNode, useEffect } from "react";
|
|
import { createPortal } from "react-dom";
|
|
|
|
interface ModalProps {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
children: ReactNode;
|
|
size?: "sm" | "md" | "lg" | "xl";
|
|
closeOnOverlayClick?: boolean;
|
|
}
|
|
|
|
const sizeClasses = {
|
|
sm: "max-w-md",
|
|
md: "max-w-2xl",
|
|
lg: "max-w-3xl",
|
|
xl: "max-w-4xl",
|
|
};
|
|
|
|
export default function Modal({
|
|
isOpen,
|
|
onClose,
|
|
children,
|
|
size = "md",
|
|
closeOnOverlayClick = true,
|
|
}: ModalProps) {
|
|
useEffect(() => {
|
|
if (isOpen) {
|
|
document.body.style.overflow = "hidden";
|
|
} else {
|
|
document.body.style.overflow = "";
|
|
}
|
|
return () => {
|
|
document.body.style.overflow = "";
|
|
};
|
|
}, [isOpen]);
|
|
|
|
if (!isOpen) return null;
|
|
|
|
const modalContent = (
|
|
<div
|
|
className="fixed inset-0 z-[200] flex items-center justify-center p-4 backdrop-blur-sm"
|
|
style={{
|
|
backgroundColor:
|
|
"color-mix(in srgb, var(--background) 80%, transparent)",
|
|
}}
|
|
onClick={closeOnOverlayClick ? onClose : undefined}
|
|
>
|
|
<div
|
|
className={`border-2 rounded-lg w-full ${sizeClasses[size]} max-h-[90vh] overflow-y-auto shadow-2xl`}
|
|
style={{
|
|
backgroundColor: "var(--card-hover)",
|
|
borderColor:
|
|
"color-mix(in srgb, var(--accent-color) 70%, transparent)",
|
|
}}
|
|
onClick={(e) => e.stopPropagation()}
|
|
>
|
|
{children}
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
// Utiliser un portal pour rendre le modal directement dans le body
|
|
if (typeof window !== "undefined") {
|
|
return createPortal(modalContent, document.body);
|
|
}
|
|
|
|
return null;
|
|
}
|