diff --git a/docs/app/page.tsx b/docs/app/page.tsx index 3d35bb81be..41000b9491 100644 --- a/docs/app/page.tsx +++ b/docs/app/page.tsx @@ -21,42 +21,42 @@ export default async function HomePage() { {/* Dark mode logos */}
{/* Light mode logos */}
diff --git a/docs/assets/GeistPixel-Square.woff2 b/docs/assets/GeistPixel-Square.woff2 new file mode 100644 index 0000000000..02cd121c51 Binary files /dev/null and b/docs/assets/GeistPixel-Square.woff2 differ diff --git a/docs/components/landing/hero-readme.tsx b/docs/components/landing/hero-readme.tsx index 883029f79e..d7966f7755 100644 --- a/docs/components/landing/hero-readme.tsx +++ b/docs/components/landing/hero-readme.tsx @@ -704,6 +704,28 @@ function ContributorsSection({ contributors: ContributorInfo[]; contributorCount: number; }) { + const wallRef = useRef(null); + const [wallNearViewport, setWallNearViewport] = useState(false); + + // Hundreds of avatars scroll through the wall; only fetch them once it's + // close to the viewport instead of relying on the browser's generous + // native lazy-loading distance. + useEffect(() => { + const wall = wallRef.current; + if (!wall) return; + const observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting) { + setWallNearViewport(true); + observer.disconnect(); + } + }, + { rootMargin: "200px" }, + ); + observer.observe(wall); + return () => observer.disconnect(); + }, []); + if (contributors.length === 0) return null; const colCount = 18; @@ -735,6 +757,7 @@ function ContributorsSection({ {contributors.length > 0 && (
- {columns.map((col, i) => ( -
-
- {[...col, ...col].map((c, j) => ( - - {c.login} -
- {c.login} -
-
- ))} + {wallNearViewport && + columns.map((col, i) => ( +
+
+ {[...col, ...col].map((c, j) => ( + + {c.login} +
+ {c.login} +
+
+ ))} +
-
- ))} + ))}
@@ -1019,7 +1043,9 @@ function DemoVideo() {