diff --git a/data/static/style.css b/data/static/style.css index 4f97cb0..3889747 100644 --- a/data/static/style.css +++ b/data/static/style.css @@ -176,7 +176,7 @@ pre code { font-size: 1rem; } -#delete-dialog { +#delete-dialog, .lightbox-dialog { padding: 0; border-radius: 4px; border: 2px solid black; @@ -190,6 +190,27 @@ pre code { padding: 20px; } +.lightbox-inner { + display: flex; + flex-direction: column; + padding: 20px; + min-width: 400px; + background-color: #c1ceb1; + gap: 10px; +} + +.lightbox-image { + max-width: 70vw; + max-height: 70vh; + object-fit: scale-down; +} + +.lightbox-nav { + display: flex; + justify-content: space-between; + align-items: center; +} + .copy-code-container { position: sticky; width: calc(100% - 4px); @@ -442,7 +463,6 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus justify-content: center; flex-direction: column; } - .contain-svg:not(.full) > svg { height: 50%; width: 50%; @@ -710,7 +730,6 @@ ul, ol { padding: 5px 10px; min-width: 36px; } - .babycode-button > * { font-size: 1rem; } diff --git a/js/ui.js b/js/ui.js index 6649015..9c640bc 100644 --- a/js/ui.js +++ b/js/ui.js @@ -21,6 +21,86 @@ function activateSelfDeactivateSibs(button) { }); } +function openLightbox(post, idx) { + lightboxCurrentPost = post; + lightboxCurrentIdx = idx; + lightboxObj.img.src = lightboxImages.get(post)[idx].src; + lightboxObj.openOriginalAnchor.href = lightboxImages.get(post)[idx].src + lightboxObj.prevButton.disabled = lightboxImages.get(post).length === 1 + lightboxObj.nextButton.disabled = lightboxImages.get(post).length === 1 + lightboxObj.imageCount.textContent = `Image ${idx + 1} of ${lightboxImages.get(post).length}` + + if (!lightboxObj.dialog.open) { + lightboxObj.dialog.showModal(); + } +} + +const modulo = (n, m) => ((n % m) + m) % m + +function lightboxNext() { + const l = lightboxImages.get(lightboxCurrentPost).length; + const target = modulo(lightboxCurrentIdx + 1, l); + openLightbox(lightboxCurrentPost, target); +} + +function lightboxPrev() { + const l = lightboxImages.get(lightboxCurrentPost).length; + const target = modulo(lightboxCurrentIdx - 1, l); + openLightbox(lightboxCurrentPost, target); +} + +function constructLightbox() { + const dialog = document.createElement("dialog"); + dialog.classList.add("lightbox-dialog"); + dialog.addEventListener("click", (e) => { + if (e.target === dialog) { + dialog.close(); + } + }) + const dialogInner = document.createElement("div"); + dialogInner.classList.add("lightbox-inner"); + dialog.appendChild(dialogInner); + const img = document.createElement("img"); + img.classList.add("lightbox-image") + dialogInner.appendChild(img); + const openOriginalAnchor = document.createElement("a") + openOriginalAnchor.text = "Open original in new window" + openOriginalAnchor.target = "_blank" + openOriginalAnchor.rel = "noopener noreferrer nofollow" + dialogInner.appendChild(openOriginalAnchor); + + const navSpan = document.createElement("span"); + navSpan.classList.add("lightbox-nav"); + const prevButton = document.createElement("button"); + prevButton.type = "button"; + prevButton.textContent = "Previous"; + prevButton.addEventListener("click", lightboxPrev); + const nextButton = document.createElement("button"); + nextButton.type = "button"; + nextButton.textContent = "Next"; + nextButton.addEventListener("click", lightboxNext); + const imageCount = document.createElement("span"); + imageCount.textContent = "Image of "; + navSpan.appendChild(prevButton); + navSpan.appendChild(imageCount); + navSpan.appendChild(nextButton); + + dialogInner.appendChild(navSpan); + return { + img: img, + dialog: dialog, + openOriginalAnchor: openOriginalAnchor, + prevButton: prevButton, + nextButton: nextButton, + imageCount: imageCount, + } +} + +let lightboxImages = new Map(); //.post-inner : Array +let lightboxObj = null; +let lightboxCurrentPost = null; +let lightboxCurrentIdx = -1; + document.addEventListener("DOMContentLoaded", () => { // tabs document.querySelectorAll(".tab-button").forEach(button => { @@ -45,4 +125,23 @@ document.addEventListener("DOMContentLoaded", () => { toggleButton.addEventListener("click", toggle); }); + + //lightboxes + lightboxObj = constructLightbox(); + document.body.appendChild(lightboxObj.dialog); + const postImages = document.querySelectorAll(".post-inner img.block-img"); + postImages.forEach(postImage => { + const belongingTo = postImage.closest(".post-inner"); + const images = lightboxImages.get(belongingTo) ?? []; + images.push({ + src: postImage.src, + alt: postImage.alt, + }); + const idx = images.length - 1; + lightboxImages.set(belongingTo, images); + postImage.style.cursor = "pointer"; + postImage.addEventListener("click", () => { + openLightbox(belongingTo, idx); + }); + }); }); diff --git a/sass/style.scss b/sass/style.scss index a2d8b70..7793da6 100644 --- a/sass/style.scss +++ b/sass/style.scss @@ -220,7 +220,7 @@ pre code { font-size: 1rem; } -#delete-dialog { +#delete-dialog, .lightbox-dialog { padding: 0; border-radius: 4px; border: 2px solid black; @@ -234,6 +234,27 @@ pre code { padding: 20px; } +.lightbox-inner { + display: flex; + flex-direction: column; + padding: 20px; + min-width: 400px; + background-color: $accent_color; + gap: 10px; +} + +.lightbox-image { + max-width: 70vw; + max-height: 70vh; + object-fit: scale-down; +} + +.lightbox-nav { + display: flex; + justify-content: space-between; + align-items: center; +} + .copy-code-container { position: sticky; // width: 100%;