diff --git a/web/.env.example b/web/.env.example index 9d151da..8641b06 100644 --- a/web/.env.example +++ b/web/.env.example @@ -14,3 +14,7 @@ # NEXT_PUBLIC_CLIENTVAR="bar" NEXT_PUBLIC_API_URL=http://localhost:8000/api + +# Github +GITHUB_OAUTH_TOKEN=xxxx + diff --git a/web/src/app/chat/components/site-header.tsx b/web/src/app/chat/components/site-header.tsx new file mode 100644 index 0000000..abfd123 --- /dev/null +++ b/web/src/app/chat/components/site-header.tsx @@ -0,0 +1,80 @@ +// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates +// SPDX-License-Identifier: MIT + +import { StarFilledIcon, GitHubLogoIcon } from "@radix-ui/react-icons"; +import Link from "next/link"; + +import { Button } from "~/components/ui/button"; +import { env } from "~/env"; + +export async function SiteHeader() { + return ( +
+
+
+ 🦌 + DeerFlow +
+
+
+ +
+
+
+
+ ); +} + +export async function StarCounter() { + let stars = 1000; // Default value + + try { + const response = await fetch( + "https://api.github.com/repos/bytedance/deer-flow", + { + headers: env.GITHUB_OAUTH_TOKEN + ? { + Authorization: `Bearer ${env.GITHUB_OAUTH_TOKEN}`, + "Content-Type": "application/json", + } + : {}, + next: { + revalidate: 3600, + }, + }, + ); + + if (response.ok) { + const data = await response.json(); + stars = data.stargazers_count ?? stars; // Update stars if API response is valid + } + } catch (error) { + console.error("Error fetching GitHub stars:", error); + } + return ( + <> + + + {stars !== null ? stars.toLocaleString() : "—"} + + + ); +} diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx index 13591a0..7ca963a 100644 --- a/web/src/app/page.tsx +++ b/web/src/app/page.tsx @@ -1,12 +1,9 @@ // Copyright (c) 2025 Bytedance Ltd. and/or its affiliates // SPDX-License-Identifier: MIT -import { GithubOutlined } from "@ant-design/icons"; -import Link from "next/link"; import { useMemo } from "react"; -import { Button } from "~/components/ui/button"; - +import { SiteHeader } from "./chat/components/site-header"; import { Jumbotron } from "./landing/components/jumbotron"; import { Ray } from "./landing/components/ray"; import { CaseStudySection } from "./landing/sections/case-study-section"; @@ -17,7 +14,7 @@ import { MultiAgentSection } from "./landing/sections/multi-agent-section"; export default function HomePage() { return (
-
+
@@ -31,28 +28,6 @@ export default function HomePage() { ); } -function Header() { - return ( -
-
-
- 🦌 - DeerFlow -
-
- -
-
-
-
- ); -} - function Footer() { const year = useMemo(() => new Date().getFullYear(), []); return ( diff --git a/web/src/env.js b/web/src/env.js index f6bbf3f..1039193 100644 --- a/web/src/env.js +++ b/web/src/env.js @@ -12,6 +12,7 @@ export const env = createEnv({ server: { NODE_ENV: z.enum(["development", "test", "production"]), AMPLITUDE_API_KEY: z.string().optional(), + GITHUB_OAUTH_TOKEN: z.string().optional(), }, /** @@ -34,6 +35,7 @@ export const env = createEnv({ NEXT_PUBLIC_STATIC_WEBSITE_ONLY: process.env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true", AMPLITUDE_API_KEY: process.env.AMPLITUDE_API_KEY, + GITHUB_OAUTH_TOKEN: process.env.GITHUB_OAUTH_TOKEN, }, /** * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially