New design.

This commit is contained in:
2026-10-14 19:29:31 +02:00
parent 047adf7b92
commit 6e60f1c117
51 changed files with 2598 additions and 2606 deletions
+38 -1
View File
@@ -1 +1,38 @@
console.log("Hi!");
import { initNav } from "./nav.js";
import { initReveal } from "./reveal.js";
import { initTimecode } from "./timecode.js";
document.documentElement.classList.add("js");
const components = {
nav: initNav,
reveal: initReveal,
timecode: initTimecode,
};
function init(root = document) {
root.querySelectorAll("[data-component]").forEach((el) => {
if (el.dataset.componentReady) {
return;
}
const fn = components[el.dataset.component];
if (fn) {
fn(el);
el.dataset.componentReady = "true";
}
});
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", start);
} else {
start();
}
function start() {
init();
// the admin UI swaps element HTML in place after edits
new MutationObserver(() => init()).observe(document.body, { childList: true, subtree: true });
}
+21
View File
@@ -0,0 +1,21 @@
export function initNav(el) {
const toggle = el.querySelector(".nav__toggle");
if (!toggle) {
return;
}
const setOpen = (open) => {
el.classList.toggle("nav--open", open);
toggle.setAttribute("aria-expanded", String(open));
};
toggle.addEventListener("click", () => setOpen(!el.classList.contains("nav--open")));
el.querySelectorAll(".nav__link").forEach((link) => link.addEventListener("click", () => setOpen(false)));
el.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
setOpen(false);
toggle.focus();
}
});
}
+25
View File
@@ -0,0 +1,25 @@
let observer = null;
function getObserver() {
if (!observer) {
observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("is-visible");
observer.unobserve(entry.target);
}
});
}, { rootMargin: "0px 0px -8% 0px", threshold: 0.05 });
}
return observer;
}
export function initReveal(el) {
if (!("IntersectionObserver" in window)) {
el.classList.add("is-visible");
return;
}
getObserver().observe(el);
}
+25
View File
@@ -0,0 +1,25 @@
const FPS = 25;
function pad(n) {
return String(n).padStart(2, "0");
}
export function initTimecode(el) {
const start = performance.now();
const tick = (now) => {
if (!el.isConnected) {
return;
}
const frames = Math.floor(((now - start) / 1000) * FPS);
const f = frames % FPS;
const s = Math.floor(frames / FPS) % 60;
const m = Math.floor(frames / (FPS * 60)) % 60;
const h = Math.floor(frames / (FPS * 3600));
el.textContent = `${pad(h)}:${pad(m)}:${pad(s)}:${pad(f)}`;
requestAnimationFrame(tick);
};
requestAnimationFrame(tick);
}