diff --git a/packages/website/src/components/site-header.tsx b/packages/website/src/components/site-header.tsx index 210b21cbd..2b765be16 100644 --- a/packages/website/src/components/site-header.tsx +++ b/packages/website/src/components/site-header.tsx @@ -1,6 +1,8 @@ import "~/styles.css"; +import { useStars } from "~/routes/__root"; export function SiteHeader() { + const { stars } = useStars(); return (
@@ -55,7 +57,7 @@ export function SiteHeader() { target="_blank" rel="noopener noreferrer" aria-label="GitHub" - className="text-muted-foreground hover:text-foreground transition-colors inline-flex items-center" + className="text-muted-foreground hover:text-foreground transition-colors inline-flex items-center gap-1.5" > + {stars && {stars}}
diff --git a/packages/website/src/routes/__root.tsx b/packages/website/src/routes/__root.tsx index 234ed8842..61f44db78 100644 --- a/packages/website/src/routes/__root.tsx +++ b/packages/website/src/routes/__root.tsx @@ -2,20 +2,31 @@ import type { ReactNode } from "react"; import { createContext, useContext } from "react"; import { Outlet, createRootRoute, HeadContent, Scripts } from "@tanstack/react-router"; import { getLatestRelease } from "~/release"; +import { getStarCount } from "~/stars"; interface ReleaseContext { version: string; } +interface StarsContext { + stars: string; +} + const ReleaseCtx = createContext({ version: "" }); +const StarsCtx = createContext({ stars: "" }); export function useRelease(): ReleaseContext { return useContext(ReleaseCtx); } +export function useStars(): StarsContext { + return useContext(StarsCtx); +} + export const Route = createRootRoute({ loader: async () => { - return getLatestRelease(); + const [release, stars] = await Promise.all([getLatestRelease(), getStarCount()]); + return { ...release, ...stars }; }, head: () => ({ meta: [ @@ -38,12 +49,14 @@ export const Route = createRootRoute({ }); function RootComponent() { - const release = Route.useLoaderData(); + const data = Route.useLoaderData(); return ( - - - - + + + + + + ); } diff --git a/packages/website/src/stars.ts b/packages/website/src/stars.ts new file mode 100644 index 000000000..cf5775e07 --- /dev/null +++ b/packages/website/src/stars.ts @@ -0,0 +1,40 @@ +import { createServerFn } from "@tanstack/react-start"; + +interface GitHubRepo { + stargazers_count: number; +} + +function formatStars(count: number): string { + if (count < 1000) return String(count); + const k = count / 1000; + return `${k % 1 === 0 ? k.toFixed(0) : k.toFixed(1)}k`; +} + +const GITHUB_REPO_URL = "https://api.github.com/repos/getpaseo/paseo"; + +async function fetchStarCount(): Promise { + try { + const res = await fetch(GITHUB_REPO_URL, { + headers: { + Accept: "application/vnd.github+json", + "User-Agent": "paseo-website", + }, + cf: { + cacheEverything: true, + cacheTtl: 60, + cacheKey: "github-repo-stars", + }, + } as RequestInit); + if (!res.ok) return ""; + + const repo = (await res.json()) as GitHubRepo; + return formatStars(repo.stargazers_count); + } catch { + return ""; + } +} + +export const getStarCount = createServerFn({ method: "GET" }).handler(async () => { + const stars = await fetchStarCount(); + return { stars }; +});