home: add Writing section; fix scroll-progress snap + nav underline reverse
build-and-deploy / build (push) Failing after 10m20s

- Scroll-progress bar: drive scaleX from scroll progress via callback form;
  the animation form snapped the bar to 0 at the bottom (progress=1 boundary)
- Nav active-underline: recompute active section from scroll position each
  frame so it tracks upward scroll too (inView-enter died on the way back up)
- Add a Writing section to the homepage with recent posts + a blog CTA
This commit is contained in:
2026-06-29 18:53:35 +10:00
parent 880b9daeac
commit 257af5d22e
2 changed files with 51 additions and 17 deletions
+31 -16
View File
@@ -67,9 +67,15 @@ function run(): void {
}
/* 4. Top scroll-progress bar — cross-browser (replaces the Chromium-only CSS
* animation-timeline). scroll() scrubs the animation by page progress. */
* animation-timeline). Drive scaleX STRAIGHT from scroll progress via the
* callback form: scroll(animate(...)) snapped the bar back to 0 at the very
* bottom (the progress=1 boundary); the callback maps 0→1 cleanly both ways. */
const bar = document.querySelector<HTMLElement>(".scroll-progress");
if (bar) scroll(animate(bar, { scaleX: [0, 1] }, { ease: "linear" }));
if (bar) {
scroll((progress: number) => {
bar.style.transform = `scaleX(${progress})`;
});
}
/* 5. Nav — animated active-section underline + tactile hover. */
initNav();
@@ -97,20 +103,29 @@ function initNav(): void {
a.addEventListener("pointerleave", () => under(a, a === active));
}
// Light up the link whose section is in view (homepage anchors only).
for (const a of links) {
const id = a.dataset.navId;
const sec = id ? document.getElementById(id) : null;
if (!sec) continue;
inView(
sec,
() => {
if (active && active !== a) under(active, false);
active = a;
under(a, true);
},
{ amount: 0.5 },
);
// Light up the link whose section is currently being read. Driven straight off
// scroll position (recomputed every frame) so it tracks BOTH directions — the
// old per-section inView(enter) fired only on the way DOWN and went dead on the
// way back up. Homepage anchor links only (Projects/Blog have no section here).
const sectioned = links.filter(
(a) => a.dataset.navId && document.getElementById(a.dataset.navId),
);
if (sectioned.length) {
const setActive = (): void => {
const line = window.innerHeight * 0.4; // section crossing the upper area is "active"
let current: HTMLAnchorElement | null = null;
for (const a of sectioned) {
const sec = document.getElementById(a.dataset.navId as string);
if (sec && sec.getBoundingClientRect().top <= line) current = a;
}
if (current !== active) {
if (active) under(active, false);
active = current;
if (current) under(current, true);
}
};
scroll(setActive);
setActive();
}
}