home: add Writing section; fix scroll-progress snap + nav underline reverse
build-and-deploy / build (push) Failing after 10m20s
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:
+20
-1
@@ -5,13 +5,16 @@ import Section from "../components/Section.astro";
|
|||||||
import About from "../components/About.astro";
|
import About from "../components/About.astro";
|
||||||
import SkillGroup from "../components/SkillGroup.astro";
|
import SkillGroup from "../components/SkillGroup.astro";
|
||||||
import ProjectCard from "../components/ProjectCard.astro";
|
import ProjectCard from "../components/ProjectCard.astro";
|
||||||
|
import PostList from "../components/PostList.astro";
|
||||||
import Contact from "../components/Contact.astro";
|
import Contact from "../components/Contact.astro";
|
||||||
import { skills } from "../data/skills";
|
import { skills } from "../data/skills";
|
||||||
|
import { getPosts } from "../lib/blog";
|
||||||
import { getCollection } from "astro:content";
|
import { getCollection } from "astro:content";
|
||||||
|
|
||||||
const featuredProjects = (await getCollection("projects", (p) => p.data.featured)).sort(
|
const featuredProjects = (await getCollection("projects", (p) => p.data.featured)).sort(
|
||||||
(a, b) => a.data.order - b.data.order,
|
(a, b) => a.data.order - b.data.order,
|
||||||
);
|
);
|
||||||
|
const recentPosts = (await getPosts()).slice(0, 3);
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout path="/">
|
<Layout path="/">
|
||||||
@@ -36,7 +39,18 @@ const featuredProjects = (await getCollection("projects", (p) => p.data.featured
|
|||||||
</p>
|
</p>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<Section id="contact" eyebrow="Get in touch" index="04" title="Let's talk infrastructure.">
|
<Section id="writing" eyebrow="Writing" index="04" title="Notes from the build.">
|
||||||
|
<p class="writing__intro" data-reveal>
|
||||||
|
Lessons from edge Kubernetes, GPUs, and running infrastructure like it matters —
|
||||||
|
written up as I go.
|
||||||
|
</p>
|
||||||
|
<PostList posts={recentPosts} />
|
||||||
|
<p class="projects__more" data-reveal>
|
||||||
|
<a class="btn" href="/blog/">Read the blog →</a>
|
||||||
|
</p>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
<Section id="contact" eyebrow="Get in touch" index="05" title="Let's talk infrastructure.">
|
||||||
<Contact />
|
<Contact />
|
||||||
</Section>
|
</Section>
|
||||||
</Layout>
|
</Layout>
|
||||||
@@ -56,4 +70,9 @@ const featuredProjects = (await getCollection("projects", (p) => p.data.featured
|
|||||||
margin-top: var(--space-6);
|
margin-top: var(--space-6);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
.writing__intro {
|
||||||
|
max-width: 52ch;
|
||||||
|
margin-bottom: var(--space-5);
|
||||||
|
color: var(--text-dim);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+31
-16
@@ -67,9 +67,15 @@ function run(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 4. Top scroll-progress bar — cross-browser (replaces the Chromium-only CSS
|
/* 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");
|
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. */
|
/* 5. Nav — animated active-section underline + tactile hover. */
|
||||||
initNav();
|
initNav();
|
||||||
@@ -97,20 +103,29 @@ function initNav(): void {
|
|||||||
a.addEventListener("pointerleave", () => under(a, a === active));
|
a.addEventListener("pointerleave", () => under(a, a === active));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Light up the link whose section is in view (homepage anchors only).
|
// Light up the link whose section is currently being read. Driven straight off
|
||||||
for (const a of links) {
|
// scroll position (recomputed every frame) so it tracks BOTH directions — the
|
||||||
const id = a.dataset.navId;
|
// old per-section inView(enter) fired only on the way DOWN and went dead on the
|
||||||
const sec = id ? document.getElementById(id) : null;
|
// way back up. Homepage anchor links only (Projects/Blog have no section here).
|
||||||
if (!sec) continue;
|
const sectioned = links.filter(
|
||||||
inView(
|
(a) => a.dataset.navId && document.getElementById(a.dataset.navId),
|
||||||
sec,
|
);
|
||||||
() => {
|
if (sectioned.length) {
|
||||||
if (active && active !== a) under(active, false);
|
const setActive = (): void => {
|
||||||
active = a;
|
const line = window.innerHeight * 0.4; // section crossing the upper area is "active"
|
||||||
under(a, true);
|
let current: HTMLAnchorElement | null = null;
|
||||||
},
|
for (const a of sectioned) {
|
||||||
{ amount: 0.5 },
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user