mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
86 lines
3.5 KiB
TypeScript
86 lines
3.5 KiB
TypeScript
import { ModalExitCode, ModalObject, ModalService } from "renderer/services/modale.service";
|
|
import { AnimatePresence, motion } from "framer-motion";
|
|
import { useObservable } from "renderer/hooks/use-observable.hook";
|
|
import { useEffect } from "react";
|
|
import { BsmIcon } from "../svgs/bsm-icon.component";
|
|
import { ThemeColorGradientSpliter } from "../shared/theme-color-gradient-spliter.component";
|
|
import { map } from "rxjs";
|
|
import { useConstant } from "renderer/hooks/use-constant.hook";
|
|
|
|
export function Modal() {
|
|
const modalSevice = ModalService.getInstance();
|
|
|
|
const modals$ = useConstant(() => modalSevice.getModalToShow());
|
|
|
|
const modals = useObservable(() => modals$);
|
|
const currentModal = useObservable<ModalObject>(() =>modals$.pipe(map(modals => modals?.at(-1))));
|
|
|
|
useEffect(() => {
|
|
const onEscape = (e: KeyboardEvent) => {
|
|
if (currentModal.options?.closable === false || e.key !== "Escape") {
|
|
return;
|
|
}
|
|
currentModal.resolver({ exitCode: ModalExitCode.CLOSED });
|
|
};
|
|
|
|
if (currentModal) {
|
|
window.addEventListener("keyup", onEscape);
|
|
} else {
|
|
window.removeEventListener("keyup", onEscape);
|
|
}
|
|
|
|
return () => {
|
|
window.removeEventListener("keyup", onEscape);
|
|
};
|
|
}, [currentModal]);
|
|
|
|
const renderCloseButton = (modal: ModalObject) => {
|
|
return (
|
|
<div
|
|
className="w-2.5 h-2.5 absolute top-2.5 right-1.5 cursor-pointer"
|
|
onClick={e => {
|
|
e.stopPropagation();
|
|
modal.resolver({ exitCode: ModalExitCode.CLOSED });
|
|
}}
|
|
>
|
|
<BsmIcon className="size-full" icon="cross" />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const renderModal = (modal: ModalObject) => {
|
|
if (!modal?.modal) { return null; }
|
|
|
|
if(modal.options?.noStyle){
|
|
return <modal.modal resolver={modal.resolver} options={modal.options} />
|
|
}
|
|
|
|
return (
|
|
<div className="relative p-4 text-gray-800 dark:text-gray-200 rounded-md shadow-lg shadow-black bg-gradient-to-br from-light-main-color-3 to-light-main-color-2 dark:from-main-color-3 dark:to-main-color-2">
|
|
<ThemeColorGradientSpliter className="absolute top-0 w-full left-0 h-1 rounded-t-md overflow-hidden"/>
|
|
{modal.options?.closable === false ? undefined : renderCloseButton(modal)}
|
|
<modal.modal resolver={modal.resolver} options={modal.options} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const onOverlayClicked = () => {
|
|
if (currentModal.options?.closable === false) {
|
|
return;
|
|
}
|
|
|
|
currentModal.resolver({ exitCode: ModalExitCode.NO_CHOICE });
|
|
}
|
|
|
|
return (
|
|
<AnimatePresence>
|
|
{currentModal ? <motion.span key={crypto.randomUUID()} onClick={onOverlayClicked} className="fixed size-full bg-black z-[90]" initial={{ opacity: 0 }} animate={{ opacity: currentModal && 0.6 }} exit={{ opacity: 0 }} transition={{ duration: 0.2 }} /> : undefined}
|
|
{modals?.map(modal => (
|
|
<motion.div key={crypto.randomUUID()} className="fixed z-[90] top-1/2 left-1/2" initial={{ y: "100vh", x: "-50%" }} animate={{y: "-50%", scale: modal === currentModal ? 1 : 0, opacity: modal === currentModal ? 1 : 0, display: modal === currentModal ? "block" : ["block", "none"]}} exit={{ y: "100vh" }}>
|
|
{renderModal(modal)}
|
|
</motion.div>
|
|
))}
|
|
</AnimatePresence>
|
|
);
|
|
}
|