Vibecode central
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
"use client";
|
||||
|
||||
import { type ReactNode, useEffect } from "react";
|
||||
|
||||
interface ModalProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
title: string;
|
||||
children: ReactNode;
|
||||
wide?: boolean;
|
||||
/**
|
||||
* When true, X + Esc prompt for confirmation before closing.
|
||||
* Backdrop clicks never close — user must use X.
|
||||
*/
|
||||
confirmClose?: boolean;
|
||||
confirmMessage?: string;
|
||||
}
|
||||
|
||||
export default function Modal({
|
||||
open,
|
||||
onClose,
|
||||
title,
|
||||
children,
|
||||
wide,
|
||||
confirmClose,
|
||||
confirmMessage = "Discard changes? Any unsaved data will be lost.",
|
||||
}: ModalProps) {
|
||||
const requestClose = () => {
|
||||
if (confirmClose && !window.confirm(confirmMessage)) return;
|
||||
onClose();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape") requestClose();
|
||||
};
|
||||
window.addEventListener("keydown", onKey);
|
||||
return () => window.removeEventListener("keydown", onKey);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [open, confirmClose]);
|
||||
|
||||
if (!open) return null;
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className={`bg-neutral-900 border border-neutral-700 rounded-lg shadow-2xl w-full ${wide ? "max-w-4xl" : "max-w-lg"} max-h-[90vh] overflow-y-auto`}
|
||||
>
|
||||
<div className="flex items-center justify-between px-6 py-4 border-b border-neutral-700">
|
||||
<h2 className="text-lg font-semibold text-neutral-100">{title}</h2>
|
||||
<button
|
||||
onClick={requestClose}
|
||||
className="text-neutral-400 hover:text-neutral-100 text-2xl leading-none"
|
||||
aria-label="Close"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div className="p-6">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user