From 30c1a07a4aa2663b009b4eb5d77a995eaf2e2c84 Mon Sep 17 00:00:00 2001 From: sajeetharan Date: Mon, 17 Aug 2026 14:34:44 +0530 Subject: [PATCH] perf: make landing page load smoothly --- app/api/developer/route.js | 2 +- app/api/developers/route.js | 2 +- app/page.jsx | 17 +-- components/DetailPanel.jsx | 11 +- components/Globe.jsx | 23 +++- components/LoadingOverlay.jsx | 187 ++++++++++---------------------- lib/developer-dataset.js | 15 +++ styles/main.css | 61 +++++++++-- tests/developer-dataset.test.js | 20 ++++ 9 files changed, 176 insertions(+), 162 deletions(-) create mode 100644 lib/developer-dataset.js create mode 100644 tests/developer-dataset.test.js diff --git a/app/api/developer/route.js b/app/api/developer/route.js index 29da0ca..683f65c 100644 --- a/app/api/developer/route.js +++ b/app/api/developer/route.js @@ -50,7 +50,7 @@ export async function GET(request) { const container = client.database(DATABASE).container(CONTAINER); const { resources } = await container.items.query({ - query: "SELECT c.id, c.login, c.name, c.avatarUrl, c.bio, c.githubUrl, c.location, c.lat, c.lng, c.followers, c.totalStars, c.totalForks, c.totalWatchers, c.totalCommits, c.topLanguage, c.languages, c.publicRepos, c.topRepos, c.soReputation, c.soAnswers, c.soAcceptRate, c.soBadges, c.soUserId, c.specialTags, c.claimed, c.claimedAt, c.metricsUpdatedAt, c.aiProfile FROM c WHERE (c.id = @id OR c.login = @id) AND (NOT IS_DEFINED(c.nomination) OR c.nomination.status = 'approved')", + query: "SELECT c.id, c.login, c.name, c.avatarUrl, c.bio, c.githubUrl, c.location, c.lat, c.lng, c.followers, c.totalStars, c.totalForks, c.totalWatchers, c.totalCommits, c.topLanguage, c.languages, c.publicRepos, c.topRepos, c.soReputation, c.soAnswers, c.soAcceptRate, c.soBadges, c.soUserId, c.score, c.scoreDimensions, c.scoreWeights, c.scoreHasSO, c.scorePercentile, c.specialTags, c.claimed, c.claimedAt, c.metricsUpdatedAt, c.aiProfile FROM c WHERE (c.id = @id OR c.login = @id) AND (NOT IS_DEFINED(c.nomination) OR c.nomination.status = 'approved')", parameters: [{ name: '@id', value: id }] }).fetchAll(); diff --git a/app/api/developers/route.js b/app/api/developers/route.js index 3426e03..b8d65f3 100644 --- a/app/api/developers/route.js +++ b/app/api/developers/route.js @@ -33,7 +33,7 @@ export async function GET() { const container = client.database(DATABASE).container(CONTAINER); const { resources } = await container.items - .query("SELECT c.id, c.login, c.name, c.avatarUrl, c.githubUrl, c.location, c.lat, c.lng, c.followers, c.publicRepos, c.totalStars, c.totalForks, c.totalWatchers, c.totalCommits, c.topLanguage, c.soUserId, c.soReputation, c.soAnswers, c.soAcceptRate, c.soBadges, c.specialTags, c.claimed, c.metricsUpdatedAt, c.collaborators, c.aiProfile FROM c WHERE NOT IS_DEFINED(c.nomination) OR c.nomination.status = 'approved'") + .query("SELECT c.id, c.login, c.name, c.avatarUrl, c.location, c.lat, c.lng, c.followers, c.publicRepos, c.totalStars, c.totalForks, c.totalCommits, c.topLanguage, c.soUserId, c.soReputation, c.soAnswers, c.soBadges, c.score, c.specialTags, c.claimed, c.metricsUpdatedAt, c.aiProfile FROM c WHERE NOT IS_DEFINED(c.nomination) OR c.nomination.status = 'approved'") .fetchAll(); return NextResponse.json(projectAgentReadinessList(resources), { diff --git a/app/page.jsx b/app/page.jsx index 409cd10..7b637d6 100644 --- a/app/page.jsx +++ b/app/page.jsx @@ -13,10 +13,7 @@ import AiProfileModal from '../components/AiProfileModal.jsx'; import IntroductionInboxModal from '../components/IntroductionInboxModal.jsx'; import QuickTour from '../components/QuickTour.jsx'; import PlatformActivityBanner from '../components/PlatformActivityBanner.jsx'; -import { scoreAll } from '../lib/scoring.js'; -import { addDeveloperRanks } from '../lib/ranking.js'; -import { enrichWithCollaborators } from '../lib/collaboration.js'; -import { withOssWorth } from '../lib/oss-worth.js'; +import { prepareDeveloperDataset } from '../lib/developer-dataset.js'; import dynamic from 'next/dynamic'; const Globe = dynamic(() => import('../components/Globe.jsx'), { ssr: false }); @@ -29,6 +26,7 @@ export default function Home() { const [filtered, setFiltered] = useState(() => cachedDeveloperDataset?.developers || []); const [selectedDev, setSelectedDev] = useState(null); const [loading, setLoading] = useState(() => !cachedDeveloperDataset); + const [loadingStage, setLoadingStage] = useState('connecting'); const [error, setError] = useState(null); const [flyTarget, setFlyTarget] = useState(null); const [selectedCountry, setSelectedCountry] = useState(''); @@ -132,7 +130,7 @@ export default function Home() { const devRes = await fetch('/api/developers', { cache: 'no-store' }); if (devRes.ok) { const raw = await devRes.json(); - const scored = enrichWithCollaborators(addDeveloperRanks(scoreAll(raw))).map(withOssWorth); + const scored = prepareDeveloperDataset(raw); setDevelopers(scored); setFiltered(scored); const claimed = new Set(raw.filter(d => d.claimed).map(d => d.login)); @@ -220,8 +218,10 @@ export default function Home() { const res = await fetch('/api/developers', { signal: AbortSignal.timeout(30000) }); if (!res.ok) throw new Error(`Failed to load data: ${res.status}`); + setLoadingStage('downloading'); const raw = await res.json(); - const scored = enrichWithCollaborators(addDeveloperRanks(scoreAll(raw))).map(withOssWorth); + setLoadingStage('preparing'); + const scored = prepareDeveloperDataset(raw); setDevelopers(scored); setFiltered(scored); // Build set of all claimed logins from data @@ -419,12 +419,13 @@ export default function Home() { setSidebarOpen(false); }, [developers]); - if (loading || error) { + if (error) { return ; } return ( -
+
+ {loading && }
{ cancelled = true; }; }, [dev.id]); + const merged = { ...dev, ...fullData }; + // Radar chart useEffect(() => { - if (!dev.scoreDimensions || !radarRef.current) return; - renderRadar(radarRef.current, dev.scoreDimensions); - }, [dev.scoreDimensions]); + if (!merged.scoreDimensions || !radarRef.current) return; + renderRadar(radarRef.current, merged.scoreDimensions); + }, [merged.scoreDimensions]); // Heatmap useEffect(() => { @@ -108,7 +110,6 @@ export default function DetailPanel({ dev, onClose, onCardGenerated, claimedLogi renderLanguages(langRef.current, langs); }, [fullData, dev.topLanguage]); - const merged = { ...dev, ...fullData }; const repos = merged.topRepos || []; const soRep = merged.soReputation || 0; const soAnswers = merged.soAnswers || 0; @@ -233,7 +234,7 @@ export default function DetailPanel({ dev, onClose, onCardGenerated, claimedLogi

Score Breakdown

- +
diff --git a/components/Globe.jsx b/components/Globe.jsx index b50f7cb..59f5e02 100644 --- a/components/Globe.jsx +++ b/components/Globe.jsx @@ -222,8 +222,25 @@ const Globe = forwardRef(function Globe({ const [countryFeatures, setCountryFeatures] = useState([]); const [hoverCountry, setHoverCountry] = useState(null); const [hoverDev, setHoverDev] = useState(null); + const [pointLimit, setPointLimit] = useState(800); const isLight = theme === 'light'; + useEffect(() => { + setPointLimit(800); + const expandedLimit = window.innerWidth < 768 ? 1200 : 2500; + + if (window.requestIdleCallback) { + const idleId = window.requestIdleCallback( + () => setPointLimit(expandedLimit), + { timeout: 2500 } + ); + return () => window.cancelIdleCallback(idleId); + } + + const timerId = window.setTimeout(() => setPointLimit(expandedLimit), 1200); + return () => window.clearTimeout(timerId); + }, [developers]); + const geoDevs = useMemo(() => { let list = developers.filter(d => d.lat != null && d.lng != null); @@ -234,8 +251,8 @@ const Globe = forwardRef(function Globe({ return list .sort((a, b) => b.score - a.score) - .slice(0, 5000); - }, [developers, selectedCountry]); + .slice(0, pointLimit); + }, [developers, pointLimit, selectedCountry]); const featuredGeoDevs = useMemo(() => ( agentNetworkVisible ? geoDevs.filter(developer => developer.agentReady) : geoDevs @@ -630,7 +647,7 @@ const Globe = forwardRef(function Globe({ pointAltitude={displayPointAltitude} pointRadius={displayPointRadius} pointColor={displayPointColor} - pointResolution={6} + pointResolution={5} htmlElementsData={avatarDevs} htmlLat={avatarLat} htmlLng={avatarLng} diff --git a/components/LoadingOverlay.jsx b/components/LoadingOverlay.jsx index 251e6a8..612f891 100644 --- a/components/LoadingOverlay.jsx +++ b/components/LoadingOverlay.jsx @@ -1,64 +1,17 @@ 'use client'; -import React, { useState, useEffect } from 'react'; +const STAGE_COPY = { + connecting: 'Connecting to the developer index', + downloading: 'Downloading developer profiles', + preparing: 'Preparing ranks and map points', +}; -const FACTS = [ - 'Mapping contributions across 150+ countries…', - 'Calculating star power and commit velocity…', - 'Ranking the world\'s top contributors…', - 'Building your interactive 3D globe…', -]; - -const FEATURED_PROFILES = ['torvalds', 'gaearon', 'sindresorhus', 'tj', 'addyosmani']; - -function AnimatedCounter({ target, duration = 2000, suffix = '' }) { - const [count, setCount] = useState(0); - - useEffect(() => { - let frame; - const startedAt = performance.now(); - - const update = (now) => { - const progress = Math.min((now - startedAt) / duration, 1); - setCount(Math.floor(target * progress)); - if (progress < 1) frame = requestAnimationFrame(update); - }; - - frame = requestAnimationFrame(update); - return () => cancelAnimationFrame(frame); - }, [target, duration]); - - return <>{count.toLocaleString()}{suffix}; -} - -export default function LoadingOverlay({ error, datasetCount }) { - const facts = [ - datasetCount === null - ? 'Counting indexed open-source developers…' - : `Indexing ${datasetCount.toLocaleString()} open-source developers…`, - ...FACTS, - ]; - const [factIndex, setFactIndex] = useState(0); - const [dots, setDots] = useState(''); - - useEffect(() => { - const factTimer = setInterval(() => { - setFactIndex(prev => (prev + 1) % facts.length); - }, 3000); - return () => clearInterval(factTimer); - }, [facts.length]); - - useEffect(() => { - const dotTimer = setInterval(() => { - setDots(prev => prev.length >= 3 ? '' : prev + '.'); - }, 400); - return () => clearInterval(dotTimer); - }, []); +export default function LoadingOverlay({ error, datasetCount, stage = 'connecting' }) { if (error) { return ( -
-
+
+
⚠️
Failed to load data
{error}
@@ -74,87 +27,57 @@ export default function LoadingOverlay({ error, datasetCount }) { } return ( -
-