714779ce27
- Lightbox lives outside #main-content so HTMX never destroys it - Gallery dispatches window events to open/close lightbox - Add hx-history-elt to #main-content so only that element is snapshotted - Remove view-transition-name to avoid duplicate conflict on history restore - Close lightbox on navigation via lightbox:close event Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
85 lines
2.9 KiB
JavaScript
85 lines
2.9 KiB
JavaScript
// ── Pivoine — main.js ─────────────────────────────────────────────
|
|
|
|
// ── HTMX progress bar ─────────────────────────────────────────────
|
|
(function () {
|
|
const bar = document.getElementById("progress-bar");
|
|
if (!bar) return;
|
|
|
|
document.body.addEventListener("htmx:beforeRequest", () => {
|
|
bar.style.width = "0";
|
|
bar.style.opacity = "1";
|
|
requestAnimationFrame(() => {
|
|
bar.style.width = "55%";
|
|
});
|
|
});
|
|
|
|
document.body.addEventListener("htmx:afterSettle", () => {
|
|
bar.style.width = "100%";
|
|
setTimeout(() => {
|
|
bar.style.opacity = "0";
|
|
setTimeout(() => { bar.style.width = "0"; }, 350);
|
|
}, 150);
|
|
});
|
|
})();
|
|
|
|
// ── Lazy-load videos (data-src attribute) ─────────────────────────
|
|
function initLazyVideos(root) {
|
|
if (!("IntersectionObserver" in window)) return;
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((entry) => {
|
|
if (!entry.isIntersecting) return;
|
|
const video = entry.target;
|
|
if (video.dataset.src) {
|
|
video.src = video.dataset.src;
|
|
video.load();
|
|
}
|
|
observer.unobserve(video);
|
|
});
|
|
},
|
|
{ rootMargin: "300px" }
|
|
);
|
|
(root || document).querySelectorAll("video[data-src]").forEach((v) => observer.observe(v));
|
|
}
|
|
|
|
initLazyVideos();
|
|
|
|
// ── Close lightbox on navigation ──────────────────────────────────
|
|
document.body.addEventListener("htmx:beforeSwap", () => {
|
|
window.dispatchEvent(new CustomEvent("lightbox:close"));
|
|
});
|
|
|
|
// ── After HTMX partial swap ────────────────────────────────────────
|
|
document.body.addEventListener("htmx:afterSwap", (e) => {
|
|
initLazyVideos(e.target);
|
|
if (window.Alpine) Alpine.initTree(e.target);
|
|
window.scrollTo({ top: 0, behavior: "instant" });
|
|
});
|
|
|
|
// ── After HTMX history restore (back / forward navigation) ────────
|
|
document.body.addEventListener("htmx:historyRestore", () => {
|
|
window.dispatchEvent(new CustomEvent("lightbox:close"));
|
|
|
|
if (window.Alpine) Alpine.store("nav").path = window.location.pathname;
|
|
|
|
const bar = document.getElementById("progress-bar");
|
|
if (bar) {
|
|
bar.style.width = "100%";
|
|
setTimeout(() => {
|
|
bar.style.opacity = "0";
|
|
setTimeout(() => { bar.style.width = "0"; }, 350);
|
|
}, 150);
|
|
}
|
|
|
|
const main = document.getElementById("main-content");
|
|
if (!main) return;
|
|
if (window.Alpine) Alpine.initTree(main);
|
|
main.querySelectorAll("video[autoplay]").forEach((v) => {
|
|
v.load();
|
|
v.play().catch(() => {});
|
|
});
|
|
window.scrollTo({ top: 0, behavior: "instant" });
|
|
window.dispatchEvent(new Event("scroll"));
|
|
});
|
|
|