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 (
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 };
+});