diff --git a/web/app/api/github-stars/route.ts b/web/app/api/github-stars/route.ts new file mode 100644 index 00000000..77b811f6 --- /dev/null +++ b/web/app/api/github-stars/route.ts @@ -0,0 +1,33 @@ +import { NextResponse } from "next/server"; + +export const revalidate = 300; // ISR: regenerate every 5 minutes + +export async function GET() { + try { + const res = await fetch( + "https://api.github.com/repos/manaflow-ai/cmux", + { + headers: { Accept: "application/vnd.github.v3+json" }, + next: { revalidate: 300 }, + } + ); + + if (!res.ok) { + return NextResponse.json({ stars: null }, { status: 502 }); + } + + const data = await res.json(); + const stars: number = data.stargazers_count; + + return NextResponse.json( + { stars }, + { + headers: { + "Cache-Control": "public, s-maxage=300, stale-while-revalidate=600", + }, + } + ); + } catch { + return NextResponse.json({ stars: null }, { status: 502 }); + } +} diff --git a/web/app/components/github-stars.tsx b/web/app/components/github-stars.tsx new file mode 100644 index 00000000..bfd50f01 --- /dev/null +++ b/web/app/components/github-stars.tsx @@ -0,0 +1,50 @@ +"use client"; + +import { useEffect, useState } from "react"; +import posthog from "posthog-js"; + +function formatStars(count: number): string { + if (count >= 1000) { + const k = count / 1000; + return k % 1 === 0 ? `${k}k` : `${k.toFixed(1)}k`; + } + return String(count); +} + +export function GitHubStarsBadge() { + const [stars, setStars] = useState(null); + + useEffect(() => { + fetch("/api/github-stars") + .then((r) => r.json()) + .then((d) => { + if (d.stars != null) setStars(d.stars); + }) + .catch(() => {}); + }, []); + + if (stars === null) return null; + + return ( + + posthog.capture("cmuxterm_github_clicked", { location: "stars_badge" }) + } + className="inline-flex items-center gap-1.5 pr-2 text-sm text-muted hover:text-foreground transition-colors" + > + + {formatStars(stars)} + + ); +} diff --git a/web/app/components/site-header.tsx b/web/app/components/site-header.tsx index bc4da923..81742b99 100644 --- a/web/app/components/site-header.tsx +++ b/web/app/components/site-header.tsx @@ -5,6 +5,7 @@ import posthog from "posthog-js"; import { NavLinks } from "./nav-links"; import { DownloadButton } from "./download-button"; import { ThemeToggle } from "../theme"; +import { GitHubStarsBadge } from "./github-stars"; import { useMobileDrawer, MobileDrawerOverlay, @@ -55,8 +56,11 @@ export function SiteHeader({ - {/* Right: Download + theme + mobile */} -
+ {/* Right: GitHub stars + Download + theme + mobile */} +
+
+ +