Improve gallery video UX and add upload-to-publish media workflow.

Stage raw files in upload/, publish with make sync-media/publish, and polish the lightbox: autoplay, remembered volume, Escape to close, and image/video icons without poster or caption clutter.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-04 23:55:43 +12:00
parent 6c215d40e6
commit 3f5235daaf
22 changed files with 644 additions and 119 deletions

View File

@@ -68,27 +68,63 @@ templ Layout(title string, preloadImage string, content templ.Component) {
document.addEventListener("DOMContentLoaded", function () {
hydrateLazyThumbs(document);
var modalRoot = document.getElementById("modal-root");
if (!modalRoot) return;
modalRoot.addEventListener("volumechange", function (event) {
if (event.target.tagName !== "VIDEO") return;
saveVideoVolume(event.target.volume);
});
});
function initModalVideos(root) {
root.querySelectorAll(".modal-video video").forEach(function (video) {
var wrap = video.closest(".modal-video");
var notice = wrap && wrap.querySelector(".video-unavailable");
video.addEventListener(
"error",
function () {
video.classList.add("video-broken");
if (notice) notice.hidden = false;
},
{ once: true },
);
video.load();
});
function closeModal() {
var modal = document.getElementById("modal-root");
if (modal) modal.innerHTML = "";
}
var galleryVideoVolumeKey = "gallery-video-volume";
function getSavedVideoVolume() {
try {
var stored = localStorage.getItem(galleryVideoVolumeKey);
if (stored === null) return null;
var v = parseFloat(stored);
if (!isFinite(v) || v < 0 || v > 1) return null;
return v;
} catch (e) {
return null;
}
}
function saveVideoVolume(volume) {
try {
localStorage.setItem(galleryVideoVolumeKey, String(volume));
} catch (e) {}
}
function playModalVideo() {
var video = document.querySelector("#modal-root video");
if (!video) return;
var saved = getSavedVideoVolume();
if (saved !== null) video.volume = saved;
var p = video.play();
if (p && typeof p.catch === "function") {
p.catch(function () {});
}
}
document.addEventListener("keydown", function (event) {
if (event.key !== "Escape") return;
var modal = document.getElementById("modal-root");
if (!modal || !modal.firstElementChild) return;
event.preventDefault();
closeModal();
});
document.body.addEventListener("htmx:afterSwap", function (event) {
hydrateLazyThumbs(event.target);
initModalVideos(event.target);
if (event.detail && event.detail.target && event.detail.target.id === "modal-root") {
playModalVideo();
}
});
})();
</script>