import { type RepoStats, repoStats, type Save, timeline } from "../mirror/queries.ts"; import { publicRepoNames } from "../server/db.ts"; import { type Html, html } from "./html.ts"; import { openPublicRepo, type PageContext, type PublicRepo, plural, relativeTime, } from "./layout.ts"; import { readmeAtHead, readmeIntro } from "./repo.ts"; /** A public repo as the front page, browse and the profile show it. `saves` are oldest first. */ export type LibraryRepo = PublicRepo & { stats: RepoStats; description: string; saves: Save[] }; export type RecentSave = { repo: string; save: Save }; /** Every public repo in card order (§20: private ones never reach a page, count or card). */ export function publicLibrary(ctx: PageContext): LibraryRepo[] { return publicRepoNames(ctx.kepr).flatMap((name) => { const repo = openPublicRepo(ctx, name); if (!repo) return []; const description = readmeIntro(name, readmeAtHead(repo))?.text ?? ""; return [{ ...repo, stats: repoStats(repo.mirror), description, saves: timeline(repo.mirror) }]; }); } /** The newest saves across the library, checkpoints never among them. */ export function recentSaves(library: LibraryRepo[], limit: number): RecentSave[] { return library .flatMap((repo) => repo.saves.slice(-limit).map((save) => ({ repo: repo.settings.name, save }))) .sort((a, b) => b.save.created_at - a.save.created_at) .slice(0, limit); } export function repoCards(library: LibraryRepo[]): Html { return html`
${library.map(repoCard)}
`; } function repoCard(repo: LibraryRepo): Html { const { name, category } = repo.settings; const { stats } = repo; return html`
${name}${plural(stats.saves, "save")}
${repo.description && html`

${repo.description}

`} ${ticks(repo.saves)}
${category && html`${category}`}${stats.language && html`${stats.language}`}${stats.updated !== null && html`${relativeTime(stats.updated)}`}
`; } // §21.2's mini-timeline: one tick per save, placed by time like the repo page's dots. function ticks(saves: Save[]): Html { const first = saves[0]?.created_at ?? 0; const span = (saves[saves.length - 1]?.created_at ?? 0) - first; const lines = saves.map((save) => { const x = span === 0 ? 50 : 1 + (98 * (save.created_at - first)) / span; return html``; }); return html``; }