Add GitHub star counter to website header
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
});
|
||||
Reference in New Issue
Block a user