Fix deferred sections staying invisible after lazy mount.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
eric 2026-08-29 03:58:21 -05:00
parent f30a7cf879
commit 11daabf065
3 changed files with 43 additions and 14 deletions

View File

@ -1171,6 +1171,12 @@ img { max-width: 100%; display: block; }
transform: translateY(0);
}
/* Deferred kits: once mounted, never stay invisible if JS timing races */
[data-deferred="ready"] .reveal {
opacity: 1;
transform: translateY(0);
}
.deferred-skeleton {
height: 120px;
margin: 24px auto;

View File

@ -129,9 +129,13 @@ export default function HomeClient(props: Props) {
}, []);
useEffect(() => {
// Above-fold reveal only — deferred sections self-reveal via WhenVisible
const nodes = document.querySelectorAll(".reveal:not(.visible)");
if (!nodes.length) return;
// Above-fold reveal; keep watching briefly for late client mounts
const mark = (root: ParentNode = document) => {
root.querySelectorAll(".reveal:not(.visible)").forEach((el, i) => {
(el as HTMLElement).style.transitionDelay = `${(i % 6) * 0.08}s`;
});
};
mark();
const observer = new IntersectionObserver(
(entries) => entries.forEach((e) => {
if (e.isIntersecting) {
@ -139,13 +143,18 @@ export default function HomeClient(props: Props) {
observer.unobserve(e.target);
}
}),
{ threshold: 0.1, rootMargin: "0px 0px -40px 0px" }
{ threshold: 0.08, rootMargin: "0px 0px -40px 0px" }
);
nodes.forEach((el, i) => {
(el as HTMLElement).style.transitionDelay = `${(i % 6) * 0.08}s`;
observer.observe(el);
});
return () => observer.disconnect();
const observeAll = () => {
document.querySelectorAll(".reveal:not(.visible)").forEach((el) => observer.observe(el));
};
observeAll();
const mo = new MutationObserver(() => observeAll());
mo.observe(document.body, { childList: true, subtree: true });
return () => {
observer.disconnect();
mo.disconnect();
};
}, []);
const toggleCompare = (slug: string) => {

View File

@ -29,7 +29,7 @@ export default function WhenVisible({
io.disconnect();
}
},
{ rootMargin, threshold: 0.01 }
{ rootMargin, threshold: 0 }
);
io.observe(el);
return () => io.disconnect();
@ -37,10 +37,24 @@ export default function WhenVisible({
useEffect(() => {
if (!show || !ref.current) return;
// Reveal animations for deferred sections without a global MutationObserver
ref.current.querySelectorAll(".reveal:not(.visible)").forEach((node) => {
node.classList.add("visible");
});
const root = ref.current;
const markVisible = () => {
root.querySelectorAll(".reveal:not(.visible)").forEach((node) => {
node.classList.add("visible");
});
};
// Lazy chunks mount after show=true — watch subtree + retry briefly
markVisible();
const mo = new MutationObserver(markVisible);
mo.observe(root, { childList: true, subtree: true });
const timers = [50, 200, 600, 1500].map((ms) => window.setTimeout(markVisible, ms));
return () => {
mo.disconnect();
timers.forEach(clearTimeout);
};
}, [show]);
return (