Add GitHub star counter to website header

This commit is contained in:
Mohamed Boudra
2026-04-12 12:53:21 +07:00
parent 44cc7a3771
commit 698a18e88f
3 changed files with 63 additions and 7 deletions
@@ -1,6 +1,8 @@
import "~/styles.css";
import { useStars } from "~/routes/__root";
export function SiteHeader() {
const { stars } = useStars();
return (
<header className="flex flex-col items-center gap-4 md:flex-row md:justify-between">
<a href="/" className="flex items-center gap-3">
@@ -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"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -66,6 +68,7 @@ export function SiteHeader() {
>
<path d="M12 0C5.37 0 0 5.484 0 12.252c0 5.418 3.438 10.013 8.205 11.637.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.738-4.042-1.61-4.042-1.61-.546-1.403-1.333-1.776-1.333-1.776-1.089-.756.084-.741.084-.741 1.205.087 1.838 1.262 1.838 1.262 1.07 1.87 2.809 1.33 3.495 1.017.108-.79.417-1.33.76-1.636-2.665-.31-5.467-1.35-5.467-6.005 0-1.327.465-2.413 1.235-3.262-.124-.31-.535-1.556.117-3.243 0 0 1.008-.33 3.3 1.248a11.2 11.2 0 0 1 3.003-.404c1.02.005 2.045.138 3.003.404 2.29-1.578 3.297-1.248 3.297-1.248.653 1.687.242 2.933.118 3.243.77.85 1.233 1.935 1.233 3.262 0 4.667-2.807 5.692-5.48 5.995.43.38.823 1.133.823 2.285 0 1.65-.015 2.98-.015 3.386 0 .315.218.694.825.576C20.565 22.26 24 17.667 24 12.252 24 5.484 18.627 0 12 0z" />
</svg>
{stars && <span className="text-sm">{stars}</span>}
</a>
</div>
</header>
+19 -6
View File
@@ -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<ReleaseContext>({ version: "" });
const StarsCtx = createContext<StarsContext>({ 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 (
<ReleaseCtx value={release}>
<RootDocument>
<Outlet />
</RootDocument>
<ReleaseCtx value={data}>
<StarsCtx value={data}>
<RootDocument>
<Outlet />
</RootDocument>
</StarsCtx>
</ReleaseCtx>
);
}
+40
View File
@@ -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<string> {
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 };
});