diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..b33e72d --- /dev/null +++ b/.env.sample @@ -0,0 +1 @@ +GITHUB_TOKEN=github_pat_xxxxxxxxxxxxxx diff --git a/.gitignore b/.gitignore index 0b304ce..21065ee 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,10 @@ next-env.d.ts .source # package管理 -.package-lock.json \ No newline at end of file +.package-lock.json + +# Agents.md +Agents.md + +# Environment variables +.env \ No newline at end of file diff --git a/app/components/Contributors.tsx b/app/components/Contributors.tsx new file mode 100644 index 0000000..f41aebd --- /dev/null +++ b/app/components/Contributors.tsx @@ -0,0 +1,47 @@ +import Image from "next/image"; +import Link from "next/link"; + +interface Contributor { + login: string; + avatar_url: string; + html_url: string; +} + +export function Contributors({ + contributors, +}: { + contributors: Contributor[]; +}) { + if (contributors.length === 0) { + return null; + } + + return ( +
+
+

贡献者

+ +
+
+ ); +} diff --git a/app/docs/[...slug]/page.tsx b/app/docs/[...slug]/page.tsx index f243b8a..a71654f 100644 --- a/app/docs/[...slug]/page.tsx +++ b/app/docs/[...slug]/page.tsx @@ -4,6 +4,8 @@ import { notFound } from "next/navigation"; import type { Metadata } from "next"; import { getMDXComponents } from "@/mdx-components"; import { GiscusComments } from "@/app/components/GiscusComments"; +import { getContributors } from "@/lib/github"; +import { Contributors } from "@/app/components/Contributors"; interface Param { params: Promise<{ @@ -19,6 +21,12 @@ export default async function DocPage({ params }: Param) { notFound(); } + // Get file path for contributors + const filePath = "app/docs/" + page.file.path; + + // Fetch contributors data on server side + const contributors = await getContributors(filePath); + const Mdx = page.data.body; return ( @@ -28,6 +36,7 @@ export default async function DocPage({ params }: Param) { {page.data.title} +
diff --git a/app/globals.css b/app/globals.css index 405c963..1aa5565 100644 --- a/app/globals.css +++ b/app/globals.css @@ -203,25 +203,6 @@ --tracking-normal: 0em; } -/* Force remove rounded corners globally for research style */ -@layer base { - .rounded, - .rounded-sm, - .rounded-md, - .rounded-lg, - .rounded-xl, - .rounded-2xl, - .rounded-3xl, - .rounded-full, - .rounded-none { - border-radius: 0 !important; - } -} - -/* - ---break--- -*/ - .dark { --background: oklch(0.2077 0.0398 265.7549); --foreground: oklch(0.9288 0.0126 255.5078); diff --git a/lib/github.ts b/lib/github.ts new file mode 100644 index 0000000..bb248ec --- /dev/null +++ b/lib/github.ts @@ -0,0 +1,57 @@ +import { cache } from "react"; + +// Define contributor data structure +interface Contributor { + login: string; + avatar_url: string; + html_url: string; +} + +// Use React's cache function for request caching and deduplication +export const getContributors = cache( + async (filePath: string): Promise => { + try { + // Use GITHUB_TOKEN environment variable for authorization to increase API rate limit + const headers: HeadersInit = {}; + if (process.env.GITHUB_TOKEN) { + headers.Authorization = `token ${process.env.GITHUB_TOKEN}`; + } + + const response = await fetch( + `https://api.github.com/repos/InvolutionHell/involutionhell.github.io/commits?path=${filePath}`, + { + headers, + // Use next.revalidate to configure cache strategy (e.g., revalidate every hour) + next: { revalidate: 3600 }, + }, + ); + + if (!response.ok) { + // If request fails, return empty array + console.error( + `Failed to fetch contributors for ${filePath}: ${response.statusText}`, + ); + return []; + } + + const commits = await response.json(); + + // Use Map to deduplicate contributors + const uniqueContributors = new Map(); + commits.forEach((commit: { author?: Contributor }) => { + if (commit.author) { + uniqueContributors.set(commit.author.login, { + login: commit.author.login, + avatar_url: commit.author.avatar_url, + html_url: commit.author.html_url, + }); + } + }); + + return Array.from(uniqueContributors.values()); + } catch (error) { + console.error(`Error fetching contributors for ${filePath}:`, error); + return []; + } + }, +);