summaryrefslogtreecommitdiff
path: root/frontend/src/components/Modal.js
diff options
context:
space:
mode:
authorAnjana Vakil <contact@anjana.dev>2025-08-26 12:40:16 -0500
committerAnjana Vakil <contact@anjana.dev>2025-08-26 12:40:16 -0500
commit1dc4f56425209d4ce1d7bb78ec8b5e7b5a755a82 (patch)
tree58d06cd695ae17302daff7a87d9096f1d39ea54a /frontend/src/components/Modal.js
reset
Diffstat (limited to 'frontend/src/components/Modal.js')
-rw-r--r--frontend/src/components/Modal.js80
1 files changed, 80 insertions, 0 deletions
diff --git a/frontend/src/components/Modal.js b/frontend/src/components/Modal.js
new file mode 100644
index 0000000..d72385b
--- /dev/null
+++ b/frontend/src/components/Modal.js
@@ -0,0 +1,80 @@
+/*
+ * Modal
+ *
+ * Pico.css - https://picocss.com
+ * Copyright 2019-2024 - Licensed under MIT
+ */
+
+// Config
+const isOpenClass = "modal-is-open";
+const openingClass = "modal-is-opening";
+const closingClass = "modal-is-closing";
+const scrollbarWidthCssVar = "--pico-scrollbar-width";
+const animationDuration = 400; // ms
+let visibleModal = null;
+
+// Toggle modal
+const toggleModal = (event) => {
+ event.preventDefault();
+ const modal = document.getElementById(event.currentTarget.dataset.target);
+ if (!modal) return;
+ modal && (modal.open ? closeModal(modal) : openModal(modal));
+};
+
+// Open modal
+const openModal = (modal) => {
+ const { documentElement: html } = document;
+ const scrollbarWidth = getScrollbarWidth();
+ if (scrollbarWidth) {
+ html.style.setProperty(scrollbarWidthCssVar, `${scrollbarWidth}px`);
+ }
+ html.classList.add(isOpenClass, openingClass);
+ setTimeout(() => {
+ visibleModal = modal;
+ html.classList.remove(openingClass);
+ }, animationDuration);
+ modal.showModal();
+};
+
+// Close modal
+const closeModal = (modal) => {
+ visibleModal = null;
+ const { documentElement: html } = document;
+ html.classList.add(closingClass);
+ setTimeout(() => {
+ html.classList.remove(closingClass, isOpenClass);
+ html.style.removeProperty(scrollbarWidthCssVar);
+ modal.close();
+ }, animationDuration);
+};
+
+// Close with a click outside
+document.addEventListener("click", (event) => {
+ if (visibleModal === null) return;
+ const modalContent = visibleModal.querySelector("article");
+ const isClickInside = modalContent.contains(event.target);
+ !isClickInside && closeModal(visibleModal);
+});
+
+// Close with Esc key
+document.addEventListener("keydown", (event) => {
+ if (event.key === "Escape" && visibleModal) {
+ closeModal(visibleModal);
+ }
+});
+
+// Get scrollbar width
+const getScrollbarWidth = () => {
+ const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
+ return scrollbarWidth;
+};
+
+
+// Initialize event listeners to open/close event pages
+export const setupModals = () => {
+ // Add open/close button handlers
+ const togglers = document.querySelectorAll('.toggle-modal');
+ for (let el of togglers) {
+ el.addEventListener("click", toggleModal);
+ }
+}; \ No newline at end of file