From 134bc9ede0461064585a0022e8679d82e0743f8d Mon Sep 17 00:00:00 2001 From: Martin Dvorak Date: Wed, 30 Sep 2026 08:13:29 +0000 Subject: [PATCH] reveal the editorial page top-to-bottom: wrap every block and cascade the first screenful --- src/app/components/EditorialSite.tsx | 66 +++++++++++++++++----------- src/app/components/editorial-ui.tsx | 34 +++++++------- src/app/globals.css | 20 +++++---- src/app/layout.tsx | 5 +++ 4 files changed, 74 insertions(+), 51 deletions(-) diff --git a/src/app/components/EditorialSite.tsx b/src/app/components/EditorialSite.tsx index df660d7..b26ae8c 100644 --- a/src/app/components/EditorialSite.tsx +++ b/src/app/components/EditorialSite.tsx @@ -168,11 +168,13 @@ export default function EditorialSite() { {/* ----------------------------------------------------------- stats */}
-
- {stats.map((s) => ( - - ))} -
+ +
+ {stats.map((s) => ( + + ))} +
+
{/* ----------------------------------------------------------- about */} @@ -243,15 +245,17 @@ export default function EditorialSite() { /> -
- -
+ +
+
    + {SERVICES.map((s) => ( +
  • + +
  • + ))} +
+
+
{/* -------------------------------------------------------- projects */} @@ -265,7 +269,8 @@ export default function EditorialSite() { /> -
    + +
      {codingProjects.map((p, i) => { const { name, status } = splitStatus(p.title); return ( @@ -288,7 +293,8 @@ export default function EditorialSite() { ); })} -
    +
+ {/* -------------------------------------------------------- hardware */} @@ -302,14 +308,16 @@ export default function EditorialSite() { /> -
+ +
{techProjects.map((t) => (

{t.title}

{t.desc}

))} -
+
+ {/* ----------------------------------------------------- contributions */} @@ -349,8 +357,9 @@ export default function EditorialSite() { /> - + {/* --------------------------------------------------------- lifting */} @@ -405,8 +415,9 @@ export default function EditorialSite() { /> -
- {socials.map((s) => ( + +
+ {socials.map((s) => ( {s.name} ))} -
+
+ {/* ---------------------------------------------------------- footer */} ); diff --git a/src/app/components/editorial-ui.tsx b/src/app/components/editorial-ui.tsx index 364879a..0f4d6fc 100644 --- a/src/app/components/editorial-ui.tsx +++ b/src/app/components/editorial-ui.tsx @@ -18,19 +18,10 @@ export function Reveal({ useEffect(() => { const el = ref.current; if (!el) return; - if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return; - - // Only animate what starts below the fold. Anything already on screen stays - // visible — otherwise the hero fades in after the section beneath it. - const rect = el.getBoundingClientRect(); - const onScreen = rect.top < window.innerHeight && rect.bottom > 0; - if (onScreen) return; - - // Hide it without a transition, then reveal when it scrolls into view. - el.style.transition = "none"; - el.classList.add("reveal-armed"); - void el.offsetHeight; - el.style.transition = ""; + if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) { + el.classList.add("is-in"); + return; + } const io = new IntersectionObserver( (entries) => { @@ -41,11 +32,22 @@ export function Reveal({ } } }, - { rootMargin: "0px 0px -10% 0px", threshold: 0.05 } + { rootMargin: "0px 0px -12% 0px", threshold: 0.08 } ); - io.observe(el); + + const rect = el.getBoundingClientRect(); + const onScreen = rect.top < window.innerHeight && rect.bottom > 0; + if (onScreen) { + // First screenful: stagger in document order so it fills top to bottom. + const all = Array.from(document.querySelectorAll(".reveal")); + const order = Math.min(Math.max(0, all.indexOf(el)), 8); + el.style.setProperty("--delay", `${delay + order * 90}ms`); + requestAnimationFrame(() => el.classList.add("is-in")); + } else { + io.observe(el); + } return () => io.disconnect(); - }, []); + }, [delay]); return (
diff --git a/src/app/globals.css b/src/app/globals.css index c941271..f36d4a9 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -33,6 +33,8 @@ --fill: rgba(235, 219, 178, 0.035); --fill-strong: rgba(235, 219, 178, 0.07); + + --ease-cinematic: cubic-bezier(0.22, 1, 0.36, 1); } /* Beats page.css's :root when the editorial theme is active. */ @@ -230,19 +232,19 @@ html[data-device="phone"] .desktop-toggle { Motion — scroll reveals only ------------------------------------------------------------------ */ -/* Visible by default: Reveal only hides elements that start below the fold, so - above-the-fold content (the hero) is never hidden while waiting for JS. */ +/* Scroll reveal. Hidden until `.is-in` lands, and every block on the editorial + page is wrapped, so the page fills in from top to bottom: the first screenful + cascades in document order on load, everything else reveals as it scrolls in. + A failed JS bundle leaves the page visible via the