From a5cc8ed600a158e26623cdd79e4a52106e897bd4 Mon Sep 17 00:00:00 2001 From: thomas Date: Sun, 30 Aug 2026 19:41:58 +0200 Subject: [PATCH] feat(website): add contributors section to landing page and fix star link - Add /api/contributors endpoint returning repo contributors (excluding bots) - Display contributor avatars on landing page below the sponsors section - Fix star icon in site header to link to /stargazers page Co-Authored-By: Claude Sonnet 4.6 --- website/src/app/layout/site-header.html | 2 +- website/src/app/pages/landing/landing.html | 17 +++++++++++++++++ website/src/app/pages/landing/landing.ts | 12 ++++++++++-- website/src/server/github-api.ts | 14 ++++++++++++++ 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/website/src/app/layout/site-header.html b/website/src/app/layout/site-header.html index 2d6c93892..655308166 100644 --- a/website/src/app/layout/site-header.html +++ b/website/src/app/layout/site-header.html @@ -40,7 +40,7 @@ {{ card.ti } + + @if (contributors().length > 0) { +
+ Contributors: + + @for (contributor of contributors(); track contributor.login) { + + + + } + +
+ } +
(() => + protected readonly sponsorsResource = httpResource<{ sponsors: GithubUser[] }>(() => this.isBrowser ? '/api/sponsors' : undefined, ); @@ -48,6 +48,14 @@ export class Landing { () => this.sponsorsResource.value()?.sponsors ?? [], ); + protected readonly contributorsResource = httpResource<{ contributors: GithubUser[] }>(() => + this.isBrowser ? '/api/contributors' : undefined, + ); + + protected readonly contributors = computed( + () => this.contributorsResource.value()?.contributors ?? [], + ); + protected readonly cards = [ { icon: 'zap', diff --git a/website/src/server/github-api.ts b/website/src/server/github-api.ts index e9db180d5..e9aa8830e 100644 --- a/website/src/server/github-api.ts +++ b/website/src/server/github-api.ts @@ -371,6 +371,20 @@ githubApi.get('/leaderboard/:board', async (req, res) => { res.json({ entries }); }); +/** All repository contributors for the landing page. */ +githubApi.get('/contributors', async (_req, res) => { + const { status, data } = await github(`/repos/${REPO}/contributors?per_page=100`, 3600); + if (status !== 200) { + res.status(503).json({ error: 'github request failed' }); + return; + } + const contributors = (data as any[]) + .filter((u) => !EXCLUDED_USERS.has(u.login) && u.type === 'User') + .map((u) => ({ login: u.login, avatar: u.avatar_url })); + res.set('Cache-Control', 'public, s-maxage=3600, stale-while-revalidate=86400'); + res.json({ contributors }); +}); + /** Repository stats for the landing page. */ githubApi.get('/stats', async (_req, res) => { const { status, data } = await github(`/repos/${REPO}`, 900);