feat(ui): project readme, language bars, and per-card language summary

ProjectPage fetches README (raw markdown) and language breakdown from
GitHub/Gitea REST APIs, rendering the readme as markdown and languages
as a colored proportional bar with labels.

Dashboard cards lazily fetch top 3 languages per repo and display them
inline. Language color map covers common languages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-05 15:28:15 +03:00
parent 80f3f7c5cb
commit ba216580ea
4 changed files with 220 additions and 16 deletions

View File

@@ -101,3 +101,33 @@ export async function fetchProjects(): Promise<ProjectSummary[]> {
if (!resp.ok) throw new Error(`projects: HTTP ${resp.status}`);
return resp.json();
}
/** Fetch repo README as rendered HTML or raw markdown. */
export async function fetchReadme(source: Source, host: string, repo: string): Promise<string | null> {
const baseUrl = source === 'github'
? `https://api.github.com/repos/${repo}/readme`
: source === 'gitea'
? `https://${host}/api/v1/repos/${repo}/readme`
: null;
if (!baseUrl) return null;
const resp = await fetch(baseUrl, {
headers: { 'Accept': 'application/vnd.github.raw+json' },
});
if (!resp.ok) return null;
return resp.text();
}
/** Fetch repo languages as { language: bytes } map. */
export async function fetchLanguages(source: Source, host: string, repo: string): Promise<Record<string, number> | null> {
const baseUrl = source === 'github'
? `https://api.github.com/repos/${repo}/languages`
: source === 'gitea'
? `https://${host}/api/v1/repos/${repo}/languages`
: null;
if (!baseUrl) return null;
const resp = await fetch(baseUrl);
if (!resp.ok) return null;
return resp.json();
}