Create Modal component

This commit is contained in:
Mathias Wagner
2025-09-09 13:31:45 +02:00
parent 8d97de06fd
commit 4d0722d282
3 changed files with 146 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
import React, { useEffect } from 'react';
import { XIcon } from '@phosphor-icons/react';
import Button from '@/common/components/Button';
import './styles.sass';
export const Modal = ({
isOpen,
onClose,
title,
children,
size = 'md',
closeOnOverlayClick = true,
showCloseButton = true,
className = ''
}) => {
useEffect(() => {
const handleEsc = (event) => {
if (event.keyCode === 27) {
onClose();
}
};
if (isOpen) {
document.addEventListener('keydown', handleEsc, false);
document.body.style.overflow = 'hidden';
}
return () => {
document.removeEventListener('keydown', handleEsc, false);
document.body.style.overflow = 'unset';
};
}, [isOpen, onClose]);
if (!isOpen) return null;
const handleOverlayClick = (e) => {
if (closeOnOverlayClick && e.target === e.currentTarget) {
onClose();
}
};
return (
<div className="modal-overlay" onClick={handleOverlayClick}>
<div className={`modal modal--${size} ${className}`} onClick={e => e.stopPropagation()}>
{(title || showCloseButton) && (
<div className="modal-header">
{title && <h2 className="modal-title">{title}</h2>}
{showCloseButton && (
<Button
variant="subtle"
size="sm"
icon={<XIcon size={16} />}
onClick={onClose}
className="modal-close"
/>
)}
</div>
)}
<div className="modal-content">
{children}
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1 @@
export { Modal as default } from './Modal.jsx';

View File

@@ -0,0 +1,80 @@
.modal-overlay
position: fixed
top: 0
left: 0
right: 0
bottom: 0
background: rgba(0, 0, 0, 0.5)
display: flex
align-items: center
justify-content: center
z-index: 1000
padding: 2rem
backdrop-filter: blur(4px)
.modal
background: var(--bg-alt)
border-radius: var(--radius-lg)
border: 1px solid var(--border)
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2)
width: 100%
max-height: 90vh
overflow: hidden
display: flex
flex-direction: column
animation: modalIn 0.2s ease-out
&--sm
max-width: 400px
&--md
max-width: 500px
&--lg
max-width: 700px
&--xl
max-width: 900px
.modal-header
display: flex
align-items: center
justify-content: space-between
padding: 1.5rem 1.5rem 0
flex-shrink: 0
.modal-title
font-size: 1.3rem
font-weight: 600
color: var(--text)
margin: 0
.modal-close
margin-left: auto
.modal-content
padding: 1.5rem
overflow-y: auto
flex: 1
@keyframes modalIn
from
opacity: 0
transform: scale(0.95) translateY(-10px)
to
opacity: 1
transform: scale(1) translateY(0)
@media (max-width: 768px)
.modal-overlay
padding: 1rem
.modal
max-width: none
margin: 0
.modal-header
padding: 1rem 1rem 0
.modal-content
padding: 1rem