Files
GameList/wwwroot/js/modals-ui.js

149 lines
4.8 KiB
JavaScript

import { t } from "./i18n.js";
import { toast } from "./dom.js";
export function openLightbox(url, title) {
const overlay = document.createElement("div");
overlay.className = "lightbox";
const content = document.createElement("div");
content.className = "lightbox-content";
const closeBtn = document.createElement("button");
closeBtn.className = "lightbox-close";
closeBtn.setAttribute("aria-label", t("lightbox.close"));
closeBtn.type = "button";
closeBtn.textContent = "✕";
const image = document.createElement("img");
image.src = url ?? "";
image.alt = title ?? "";
const caption = document.createElement("p");
caption.textContent = title ?? "";
content.append(closeBtn, image, caption);
overlay.appendChild(content);
overlay.addEventListener("click", (e) => {
if (
e.target.classList.contains("lightbox") ||
e.target.classList.contains("lightbox-close")
) {
overlay.remove();
}
});
document.body.appendChild(overlay);
}
export function openConfirmModal({
title,
body,
confirmLabel,
cancelLabel = t("modal.cancel"),
confirmClass = null,
requirePassword = false,
passwordLabel = t("auth.password"),
onConfirm,
}) {
const overlay = document.createElement("div");
overlay.className = "edit-modal";
const panel = document.createElement("div");
panel.className = "edit-panel";
const header = document.createElement("div");
header.className = "edit-header";
const heading = document.createElement("h3");
heading.textContent = title ?? "";
const closeBtn = document.createElement("button");
closeBtn.className = "lightbox-close";
closeBtn.setAttribute("aria-label", t("modal.close"));
closeBtn.type = "button";
closeBtn.textContent = "x";
header.append(heading, closeBtn);
const bodyWrap = document.createElement("div");
bodyWrap.className = "edit-body";
const bodyText = document.createElement("p");
bodyText.textContent = body ?? "";
bodyWrap.appendChild(bodyText);
panel.append(header, bodyWrap);
const close = () => overlay.remove();
const actions = document.createElement("div");
actions.className = "stack horizontal confirm-actions";
const confirmBtn = document.createElement("button");
if (confirmClass) confirmBtn.className = confirmClass;
confirmBtn.textContent = confirmLabel ?? t("modal.confirm");
confirmBtn.disabled = requirePassword;
actions.append(confirmBtn);
if (cancelLabel !== null && cancelLabel !== undefined) {
const cancelBtn = document.createElement("button");
cancelBtn.className = "ghost";
cancelBtn.type = "button";
cancelBtn.textContent = cancelLabel;
actions.append(cancelBtn);
cancelBtn.addEventListener("click", close);
}
const bodyContainer = bodyWrap;
let passwordInput = null;
if (requirePassword && bodyContainer) {
const field = document.createElement("label");
field.className = "stack";
const label = document.createElement("span");
label.className = "label";
label.textContent = passwordLabel;
passwordInput = document.createElement("input");
passwordInput.type = "password";
passwordInput.autocomplete = "current-password";
field.append(label, passwordInput);
bodyContainer.appendChild(field);
passwordInput.addEventListener("input", () => {
confirmBtn.disabled = !(passwordInput.value || "").trim();
});
}
bodyContainer?.appendChild(actions);
overlay.addEventListener("click", (e) => {
if (
e.target.classList.contains("edit-modal") ||
e.target.classList.contains("lightbox-close")
) {
close();
}
});
confirmBtn.addEventListener("click", async () => {
try {
await onConfirm?.(close, { password: passwordInput?.value ?? "" });
} catch (err) {
toast(err.message, true);
}
});
overlay.appendChild(panel);
document.body.appendChild(overlay);
}
export function openResultsRelockModal() {
openConfirmModal({
title: t("results.relockedTitle"),
body: t("results.relockedBody"),
confirmLabel: t("results.relockedConfirm"),
cancelLabel: null,
onConfirm: (close) => close(),
});
}
export function openSuggestionsChangedModal(names) {
const uniq = Array.from(new Set(names)).filter(Boolean);
if (uniq.length === 0) return;
openConfirmModal({
title: t("vote.listUpdatedTitle"),
body: t("vote.listUpdatedBody", { names: uniq.join(", ") }),
confirmLabel: t("vote.listUpdatedConfirm"),
cancelLabel: null,
onConfirm: (close) => close(),
});
}