From 213eac3fdad2e4c7e767978b9a44d101771176a8 Mon Sep 17 00:00:00 2001 From: omaroughriss Date: Tue, 30 Sep 2025 17:57:16 +0200 Subject: [PATCH] Add generic modal --- components/ui/modal/Modal.css | 104 ++++++++++++++++++++++++++++++++++ components/ui/modal/Modal.tsx | 49 ++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 components/ui/modal/Modal.css create mode 100644 components/ui/modal/Modal.tsx diff --git a/components/ui/modal/Modal.css b/components/ui/modal/Modal.css new file mode 100644 index 0000000..6da31ab --- /dev/null +++ b/components/ui/modal/Modal.css @@ -0,0 +1,104 @@ +/* Modal Overlay */ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + padding: 1rem; +} + +/* Modal Container */ +.modal-container { + background: white; + border-radius: 0.75rem; + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); + max-height: 90vh; + overflow: hidden; + display: flex; + flex-direction: column; + width: 100%; +} + +.modal-sm { + max-width: 28rem; +} + +.modal-md { + max-width: 32rem; +} + +.modal-lg { + max-width: 48rem; +} + +.modal-xl { + max-width: 64rem; +} + +/* Modal Header */ +.modal-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 1.5rem; + border-bottom: 1px solid #e5e7eb; + background: #f9fafb; +} + +.modal-title { + font-size: 1.25rem; + font-weight: 600; + color: #111827; + margin: 0; +} + +.modal-close-button { + display: flex; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + border: none; + background: none; + border-radius: 0.375rem; + color: #6b7280; + cursor: pointer; + transition: all 0.2s; +} + +.modal-close-button:hover { + background-color: #f3f4f6; + color: #374151; +} + +/* Modal Content */ +.modal-content { + flex: 1; + overflow-y: auto; + padding: 0; +} + +/* Responsive */ +@media (max-width: 640px) { + .modal-overlay { + padding: 0.5rem; + } + + .modal-container { + max-height: 95vh; + } + + .modal-header { + padding: 1rem; + } + + .modal-title { + font-size: 1.125rem; + } +} diff --git a/components/ui/modal/Modal.tsx b/components/ui/modal/Modal.tsx new file mode 100644 index 0000000..7adbe04 --- /dev/null +++ b/components/ui/modal/Modal.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { X } from 'lucide-react'; +import './Modal.css'; + +interface ModalProps { + isOpen: boolean; + onClose: () => void; + title: string; + children: React.ReactNode; + size?: 'sm' | 'md' | 'lg' | 'xl'; +} + +const Modal: React.FC = ({ + isOpen, + onClose, + title, + children, + size = 'md' +}) => { + if (!isOpen) return null; + + const handleBackdropClick = (e: React.MouseEvent) => { + if (e.target === e.currentTarget) { + onClose(); + } + }; + + return ( +
+
+
+

{title}

+ +
+
+ {children} +
+
+
+ ); +}; + +export default Modal;