소스 검색

feat(web): fetch GitHub star count dynamically (#266)

* feat(web): fetch GitHub star count dynamically

Replace the hardcoded "12k" star count in the header with a live value
from the GitHub API, revalidated every 24 hours. Gracefully hides the
count if the fetch fails.

* fix: add GITHUB_TOKEN to turbo.json globalEnv

* fix: remove GITHUB_TOKEN usage from star count fetch
Chris Tate 3 달 전
부모
커밋
6e5ea186de
3개의 변경된 파일36개의 추가작업 그리고 7개의 파일을 삭제
  1. 5 2
      apps/web/app/(main)/layout.tsx
  2. 11 5
      apps/web/components/header.tsx
  3. 20 0
      apps/web/lib/github.ts

+ 5 - 2
apps/web/app/(main)/layout.tsx

@@ -1,13 +1,16 @@
 import { Header } from "@/components/header";
+import { getStarCount } from "@/lib/github";
 
-export default function MainLayout({
+export default async function MainLayout({
   children,
 }: {
   children: React.ReactNode;
 }) {
+  const stars = await getStarCount();
+
   return (
     <div className="min-h-screen flex flex-col">
-      <Header />
+      <Header stars={stars} />
       <main className="flex-1">{children}</main>
     </div>
   );

+ 11 - 5
apps/web/components/header.tsx

@@ -19,7 +19,13 @@ const navLinks = [
   { href: "/docs", label: "Docs" },
 ];
 
-function GitHubLink({ className }: { className?: string }) {
+function GitHubLink({
+  className,
+  stars,
+}: {
+  className?: string;
+  stars?: string;
+}) {
   return (
     <a
       href="https://github.com/vercel-labs/json-render"
@@ -38,12 +44,12 @@ function GitHubLink({ className }: { className?: string }) {
       >
         <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z" />
       </svg>
-      <span>12k</span>
+      {stars && <span>{stars}</span>}
     </a>
   );
 }
 
-export function Header() {
+export function Header({ stars }: { stars?: string }) {
   const pathname = usePathname();
   const [mobileOpen, setMobileOpen] = useState(false);
 
@@ -122,14 +128,14 @@ export function Header() {
             </Link>
           ))}
           <Search />
-          <GitHubLink />
+          <GitHubLink stars={stars} />
           <ThemeToggle />
         </nav>
 
         {/* Mobile nav */}
         <div className="flex sm:hidden items-center gap-3">
           <Search />
-          <GitHubLink />
+          <GitHubLink stars={stars} />
           <Sheet open={mobileOpen} onOpenChange={setMobileOpen}>
             <SheetTrigger
               className="flex items-center justify-center"

+ 20 - 0
apps/web/lib/github.ts

@@ -0,0 +1,20 @@
+const REPO = "vercel-labs/json-render";
+const REVALIDATE = 86400;
+
+export async function getStarCount(): Promise<string> {
+  try {
+    const res = await fetch(`https://api.github.com/repos/${REPO}`, {
+      headers: { Accept: "application/vnd.github.v3+json" },
+      next: { revalidate: REVALIDATE },
+    });
+    if (!res.ok) return "";
+    const data = await res.json();
+    const count = data.stargazers_count;
+    if (typeof count !== "number") return "";
+    if (count >= 1000)
+      return `${(count / 1000).toFixed(count >= 10000 ? 0 : 1)}k`;
+    return String(count);
+  } catch {
+    return "";
+  }
+}