Skip to content

Commit 0786575

Browse files
committed
Enrich open source contribution details
1 parent af0db5d commit 0786575

7 files changed

Lines changed: 329 additions & 10 deletions

File tree

app/detail-page.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ type DetailPageProps = {
3737
previous?: { href: string; label: string };
3838
next?: { href: string; label: string };
3939
externalIcon?: ReactNode;
40+
summaryStrip?: ReactNode;
41+
showcase?: ReactNode;
4042
};
4143

4244
const stepIcons = {
@@ -64,6 +66,8 @@ export default function DetailPage({
6466
previous,
6567
next,
6668
externalIcon,
69+
summaryStrip,
70+
showcase,
6771
}: DetailPageProps) {
6872
return <main className="detail-page" style={{ '--detail-accent': accent } as CSSProperties}>
6973
<nav className="detail-nav" aria-label="详情页导航">
@@ -88,6 +92,8 @@ export default function DetailPage({
8892
<aside className="detail-highlight"><small>KEY TAKEAWAY</small><strong>{highlight}</strong></aside>
8993
</section>
9094

95+
{summaryStrip}
96+
9197
{metrics && metrics.length > 0 && <section className="detail-metrics" aria-label="项目指标">
9298
{metrics.map(([label, value]) => <div key={label}><span>{label}</span><strong>{value}</strong></div>)}
9399
</section>}
@@ -110,6 +116,8 @@ export default function DetailPage({
110116
</div>
111117
</section>
112118

119+
{showcase}
120+
113121
<section className="detail-final-cta">
114122
<div><small>UPSTREAM / PROJECT</small><h2>继续查看公开项目</h2><p>站内页面解释我的工作,外部链接保留项目原始上下文与最新进展。</p></div>
115123
<a href={externalHref} target="_blank" rel="noopener noreferrer">{externalIcon ?? <PiGithubLogo aria-hidden="true" />}{externalLabel}<PiArrowUpRightBold aria-hidden="true" /></a>

app/github-project-stats.tsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
'use client';
2+
3+
import { useEffect, useState } from 'react';
4+
import { PiArrowUpRightBold, PiGitPullRequest, PiStarFill } from 'react-icons/pi';
5+
6+
const cacheDuration = 30 * 60 * 1000;
7+
8+
function formatStars(value: number) {
9+
if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(value >= 10_000_000 ? 0 : 1)}m`;
10+
if (value >= 1_000) return `${(value / 1_000).toFixed(value >= 100_000 ? 0 : 1)}k`;
11+
return value.toLocaleString('en-US');
12+
}
13+
14+
export default function GitHubProjectStats({ repositoryUrl, prUrl }: { repositoryUrl: string; prUrl: string }) {
15+
const [stars, setStars] = useState<number | null>(null);
16+
const repository = new URL(repositoryUrl).pathname.replace(/^\//, '').replace(/\/$/, '');
17+
const prNumber = new URL(prUrl).pathname.split('/').filter(Boolean).at(-1);
18+
19+
useEffect(() => {
20+
const controller = new AbortController();
21+
const cacheKey = `github-stars:${repository}`;
22+
23+
const load = async () => {
24+
try {
25+
const cached = window.localStorage.getItem(cacheKey);
26+
if (cached) {
27+
const parsed = JSON.parse(cached) as { value: number; updatedAt: number };
28+
if (typeof parsed.value === 'number') {
29+
setStars(parsed.value);
30+
if (Date.now() - parsed.updatedAt < cacheDuration) return;
31+
}
32+
}
33+
const response = await fetch(`https://api.github.com/repos/${repository}`, {
34+
headers: { Accept: 'application/vnd.github+json' },
35+
signal: controller.signal,
36+
});
37+
if (!response.ok) return;
38+
const data = await response.json() as { stargazers_count?: number };
39+
if (typeof data.stargazers_count !== 'number') return;
40+
window.localStorage.setItem(cacheKey, JSON.stringify({ value: data.stargazers_count, updatedAt: Date.now() }));
41+
setStars(data.stargazers_count);
42+
} catch {
43+
// Keep the cached value or the loading fallback when GitHub rate-limits the request.
44+
}
45+
};
46+
47+
void load();
48+
return () => controller.abort();
49+
}, [repository]);
50+
51+
return <section className="github-detail-stats" aria-label="GitHub 项目信息">
52+
<div><PiStarFill aria-hidden="true" /><span>GitHub Stars</span><strong title={stars ? `${stars.toLocaleString('en-US')} Stars` : undefined}>{stars === null ? '—' : formatStars(stars)}</strong><small>每 30 分钟更新</small></div>
53+
<a href={prUrl} target="_blank" rel="noopener noreferrer"><PiGitPullRequest aria-hidden="true" /><span>我的 Pull Request</span><strong>#{prNumber} · MERGED</strong><small>查看上游合并记录 <PiArrowUpRightBold aria-hidden="true" /></small></a>
54+
</section>;
55+
}

0 commit comments

Comments
 (0)