From 2e6337d6d9fb68c8c9fc53470b54862de93e530b Mon Sep 17 00:00:00 2001 From: desko27 Date: Thu, 18 Jun 2026 18:26:20 +0200 Subject: [PATCH 1/3] feat(web): show GitHub star count in Star CTAs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Header button becomes a segmented "Star | 1.2k" on desktop (the familiar GitHub pattern) and a compact icon + count on mobile. The landing CTA gains a "· 1.2k" suffix. Count is fetched at build time via a shared, memoized getStarCount() helper with a fallback for failed builds, and surfaced in each button's aria-label. --- sites/web/src/components/Header.astro | 53 +++++++++++++++++++-------- sites/web/src/lib/github.ts | 31 ++++++++++++++++ sites/web/src/pages/index.astro | 8 +++- 3 files changed, 74 insertions(+), 18 deletions(-) create mode 100644 sites/web/src/lib/github.ts diff --git a/sites/web/src/components/Header.astro b/sites/web/src/components/Header.astro index fa1881e..d438ff7 100644 --- a/sites/web/src/components/Header.astro +++ b/sites/web/src/components/Header.astro @@ -1,7 +1,10 @@ --- +import { formatStarCount, getStarCount } from '~/lib/github' import { MobileNav } from './MobileNav' import { ThemeToggle } from './ThemeToggle' +const starsLabel = formatStarCount(await getStarCount()) + const navItems = [ { href: '/why', label: 'Why' }, { href: '/examples', label: 'Examples' }, @@ -79,32 +82,50 @@ const mobileLinks = [...navItems, referenceLink] {referenceLink.label} + {/* Segmented "Star | count" on desktop (the familiar GitHub pattern); + collapses to a compact icon + count on mobile — no divider, no + second segment background. */} - + + - - - + {starsLabel} +
diff --git a/sites/web/src/lib/github.ts b/sites/web/src/lib/github.ts new file mode 100644 index 0000000..f3a20c3 --- /dev/null +++ b/sites/web/src/lib/github.ts @@ -0,0 +1,31 @@ +const REPO = 'desko27/react-call' + +// Used when the build-time fetch fails (offline CI, GitHub down, rate limit). +// Roughly tracks the real count so the UI never shows an absurd number — it +// only matters on the rare failed build, and refreshes on the next deploy. +const FALLBACK_STARS = 1200 + +// Astro renders Header on every page, so memoize: one network request per +// build regardless of how many pages/components ask for the count. +let cached: Promise | undefined + +export function getStarCount(): Promise { + if (!cached) { + cached = fetch(`https://api.github.com/repos/${REPO}`, { + headers: { Accept: 'application/vnd.github+json' }, + }) + .then((res) => { + if (!res.ok) throw new Error(`GitHub API ${res.status}`) + return res.json() as Promise<{ stargazers_count: number }> + }) + .then((data) => data.stargazers_count) + .catch(() => FALLBACK_STARS) + } + return cached +} + +// 1215 -> "1.2k", 980 -> "980", 12345 -> "12.3k". Trailing ".0" is dropped. +export function formatStarCount(n: number): string { + if (n < 1000) return String(n) + return `${(n / 1000).toFixed(1).replace(/\.0$/, '')}k` +} diff --git a/sites/web/src/pages/index.astro b/sites/web/src/pages/index.astro index 1d62eb3..8617fb8 100644 --- a/sites/web/src/pages/index.astro +++ b/sites/web/src/pages/index.astro @@ -6,10 +6,12 @@ import { HowItLives } from '~/components/landing/HowItLives' import { MutationFlowSection } from '~/components/landing/MutationFlowSection' import { NotJustConfirmations } from '~/components/landing/NotJustConfirmations' import { StackSection } from '~/components/landing/StackSection' +import { formatStarCount, getStarCount } from '~/lib/github' import Base from '~/layouts/Base.astro' import { getAllExamples } from '~/lib/examples' const exampleCount = getAllExamples().length +const starsLabel = formatStarCount(await getStarCount()) --- @@ -134,7 +136,7 @@ const onDelete = async () => { href="https://github.com/desko27/react-call" target="_blank" rel="noopener noreferrer" - aria-label="Star react-call on GitHub" + aria-label={`Star react-call on GitHub — ${starsLabel} stars`} class="inline-flex items-center gap-2 rounded-md border border-[var(--color-border-strong)] bg-[var(--color-bg)] px-4 py-2 font-medium text-[var(--color-fg)] transition-colors hover:bg-[var(--color-bg-muted)]" > { d="M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z" > - Star on GitHub + Star on GitHub + + {starsLabel}
From bc80ac0b5b16ea0cd3e4e206ed31e06e484a4e9d Mon Sep 17 00:00:00 2001 From: desko27 Date: Thu, 18 Jun 2026 18:33:36 +0200 Subject: [PATCH 2/3] feat(web): label the header CTA "GitHub" instead of "Star" --- sites/web/src/components/Header.astro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sites/web/src/components/Header.astro b/sites/web/src/components/Header.astro index d438ff7..a23ac93 100644 --- a/sites/web/src/components/Header.astro +++ b/sites/web/src/components/Header.astro @@ -82,7 +82,7 @@ const mobileLinks = [...navItems, referenceLink] {referenceLink.label} - {/* Segmented "Star | count" on desktop (the familiar GitHub pattern); + {/* Segmented "GitHub | count" on desktop (the familiar GitHub pattern); collapses to a compact icon + count on mobile — no divider, no second segment background. */} - +