more more more

This commit is contained in:
Michael Freno
2026-01-06 11:58:12 -05:00
parent 46f1efcd79
commit 1f661f4f89
5 changed files with 234 additions and 176 deletions

View File

@@ -0,0 +1,87 @@
import { Show, onMount, onCleanup, type JSX } from "solid-js";
import { Portal } from "solid-js/web";
import Xmark from "~/components/icons/Xmark";
export interface ModalProps {
/** Controls modal visibility */
open: boolean;
/** Callback when modal should close */
onClose: () => void;
/** Modal title (optional) */
title?: string | JSX.Element;
/** Modal content */
children: JSX.Element;
/** Action buttons (optional) */
actions?: JSX.Element;
/** Additional CSS classes for modal container */
class?: string;
}
export default function Modal(props: ModalProps) {
const handleBackdropClick = (e: MouseEvent) => {
if (e.target === e.currentTarget) {
props.onClose();
}
};
const handleEscapeKey = (e: KeyboardEvent) => {
if (e.key === "Escape") {
props.onClose();
}
};
onMount(() => {
if (props.open) {
document.addEventListener("keydown", handleEscapeKey);
}
});
onCleanup(() => {
document.removeEventListener("keydown", handleEscapeKey);
});
return (
<Show when={props.open}>
<Portal>
<div
class="fixed inset-0 z-50 flex items-center justify-center bg-black/50"
onClick={handleBackdropClick}
role="dialog"
aria-modal="true"
>
<div
class={`bg-base fade-in relative mx-4 max-w-md rounded-md px-8 py-4 shadow-lg ${props.class || ""}`}
onClick={(e) => e.stopPropagation()}
>
<button
class="absolute top-4 right-4"
onClick={props.onClose}
aria-label="Close modal"
>
<Xmark
strokeWidth={0.5}
color="var(--color-text)"
height={50}
width={50}
/>
</button>
<Show when={props.title}>
<div class="py-4 text-center text-3xl tracking-wide">
{props.title}
</div>
</Show>
<div class="modal-content">{props.children}</div>
<Show when={props.actions}>
<div class="modal-actions">{props.actions}</div>
</Show>
</div>
</div>
</Portal>
</Show>
);
}
export { Modal };