library.ts

1.9 KB · raw

1import { newestSaves, type RepoStats, repoStats, type Save } from "../mirror/queries.ts";2import { publicRepoNames } from "../server/db.ts";3import { type Html, html } from "./html.ts";4import { openPublicRepo, type PageContext, type PublicRepo, plural } from "./layout.ts";5import { repoIntro } from "./repo.ts";67/** A public repo as the front page, browse and the profile show it. */8export type LibraryRepo = PublicRepo & { stats: RepoStats; description: string };910export type RecentSave = { repo: string; save: Save };1112/** Every public repo in card order (§20: private ones never reach a page, count or card). */13export function publicLibrary(ctx: PageContext): LibraryRepo[] {14	return publicRepoNames(ctx.kepr).flatMap((name) => {15		const repo = openPublicRepo(ctx, name);16		if (!repo) return [];17		const description = repoIntro(repo)?.text ?? "";18		return [{ ...repo, stats: repoStats(repo.mirror), description }];19	});20}2122/** The newest saves across the library, checkpoints never among them. */23export function recentSaves(library: LibraryRepo[], limit: number): RecentSave[] {24	return library25		.flatMap((repo) =>26			newestSaves(repo.mirror, limit).map((save) => ({ repo: repo.settings.name, save })),27		)28		.sort((a, b) => b.save.created_at - a.save.created_at)29		.slice(0, limit);30}3132export function repoCards(library: LibraryRepo[]): Html {33	return html`<div class="card-grid">${library.map(repoCard)}</div>`;34}3536// Kepr 2's card: name, save count, the description, and the category.37function repoCard(repo: LibraryRepo): Html {38	const { name, category } = repo.settings;39	return html`<a class="repo-card" href="/${name}">40<div class="repo-card-head"><span class="repo-card-name">${41		name42	}</span><span class="repo-card-saves mono">${plural(repo.stats.saves, "save")}</span></div>43${repo.description && html`<p class="repo-card-desc">${repo.description}</p>`}44${category && html`<p class="repo-card-cat">${category}</p>`}45</a>`;46}