123 lines
3.5 KiB
JavaScript
123 lines
3.5 KiB
JavaScript
/**
|
||
* Diagram Lightbox — fullscreen viewer for Kroki-rendered diagrams.
|
||
*
|
||
* Behaviour:
|
||
* - Clicking any Kroki diagram (<img alt="Kroki">) opens a fullscreen
|
||
* overlay showing the diagram at maximum viewport size.
|
||
* - The overlay has an X close button in the top-right corner.
|
||
* - Pressing Escape or clicking the backdrop closes the overlay.
|
||
* - Works with mkdocs-material instant-loading / SPA navigation.
|
||
*/
|
||
(function () {
|
||
"use strict";
|
||
|
||
/** The overlay element (created once, reused). */
|
||
var overlay = null;
|
||
|
||
/** The <img> inside the overlay. */
|
||
var overlayImg = null;
|
||
|
||
/** The close button. */
|
||
var closeBtn = null;
|
||
|
||
/**
|
||
* Build the lightbox DOM elements and append to <body>.
|
||
* Called once on first use.
|
||
*/
|
||
function ensureOverlay() {
|
||
if (overlay) return;
|
||
|
||
overlay = document.createElement("div");
|
||
overlay.className = "diagram-lightbox";
|
||
overlay.setAttribute("role", "dialog");
|
||
overlay.setAttribute("aria-modal", "true");
|
||
overlay.setAttribute("aria-label", "Diagram fullscreen view");
|
||
|
||
overlayImg = document.createElement("img");
|
||
overlayImg.alt = "Diagram fullscreen";
|
||
|
||
closeBtn = document.createElement("button");
|
||
closeBtn.className = "diagram-lightbox-close";
|
||
closeBtn.setAttribute("aria-label", "Close fullscreen diagram");
|
||
closeBtn.innerHTML = "×"; // × character
|
||
closeBtn.type = "button";
|
||
|
||
overlay.appendChild(overlayImg);
|
||
overlay.appendChild(closeBtn);
|
||
document.body.appendChild(overlay);
|
||
|
||
// Close on button click
|
||
closeBtn.addEventListener("click", function (e) {
|
||
e.stopPropagation();
|
||
closeLightbox();
|
||
});
|
||
|
||
// Close on backdrop click (but not on the image itself)
|
||
overlay.addEventListener("click", function (e) {
|
||
if (e.target === overlay) {
|
||
closeLightbox();
|
||
}
|
||
});
|
||
|
||
// Close on Escape key
|
||
document.addEventListener("keydown", function (e) {
|
||
if (e.key === "Escape" && overlay.classList.contains("active")) {
|
||
closeLightbox();
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Open the lightbox with the given image source.
|
||
*/
|
||
function openLightbox(src) {
|
||
ensureOverlay();
|
||
overlayImg.src = src;
|
||
overlay.classList.add("active");
|
||
// Prevent background scrolling
|
||
document.body.style.overflow = "hidden";
|
||
// Move focus to close button for accessibility
|
||
closeBtn.focus();
|
||
}
|
||
|
||
/**
|
||
* Close the lightbox.
|
||
*/
|
||
function closeLightbox() {
|
||
if (!overlay) return;
|
||
overlay.classList.remove("active");
|
||
document.body.style.overflow = "";
|
||
}
|
||
|
||
/**
|
||
* Attach click handlers to all Kroki diagram images on the page.
|
||
* Safe to call multiple times (skips already-bound images).
|
||
*/
|
||
function bindDiagrams() {
|
||
var imgs = document.querySelectorAll('img[alt="Kroki"]');
|
||
imgs.forEach(function (img) {
|
||
if (img.dataset.lightboxBound) return;
|
||
img.dataset.lightboxBound = "1";
|
||
|
||
img.addEventListener("click", function () {
|
||
openLightbox(img.src);
|
||
});
|
||
});
|
||
}
|
||
|
||
// ── Bootstrap ─────────────────────────────────────────────────────────
|
||
|
||
if (document.readyState === "loading") {
|
||
document.addEventListener("DOMContentLoaded", bindDiagrams);
|
||
} else {
|
||
bindDiagrams();
|
||
}
|
||
|
||
// Re-bind after instant navigation (mkdocs-material SPA mode)
|
||
if (typeof document$ !== "undefined") {
|
||
document$.subscribe(function () {
|
||
bindDiagrams();
|
||
});
|
||
}
|
||
})();
|