sheets.ts (2473B)
1 import { getCollection, type CollectionEntry } from 'astro:content'; 2 import { CATEGORIES } from './taxonomy'; 3 4 export type Sheet = CollectionEntry<'sheets'>; 5 6 export async function allSheets(): Promise<Sheet[]> { 7 const sheets = await getCollection('sheets', ({ data }) => data.draft !== true); 8 return sheets.sort((a, b) => a.data.title.localeCompare(b.data.title)); 9 } 10 11 export function sheetHref(entry: Sheet): string { 12 return `sheets/${entry.id}`; 13 } 14 15 export function sheetCategories(entry: Sheet): string[] { 16 return [...new Set([entry.data.category, ...entry.data.alsoIn])]; 17 } 18 19 /** Sheets grouped by category, in taxonomy order. */ 20 export async function sheetsByCategory(): Promise<{ slug: string; items: Sheet[] }[]> { 21 const sheets = await allSheets(); 22 return CATEGORIES.map((c) => ({ 23 slug: c.slug, 24 items: sheets.filter((s) => sheetCategories(s).includes(c.slug)), 25 })); 26 } 27 28 export async function categoryCounts(): Promise<Record<string, number>> { 29 const sheets = await allSheets(); 30 const counts: Record<string, number> = {}; 31 for (const s of sheets) { 32 for (const category of sheetCategories(s)) counts[category] = (counts[category] ?? 0) + 1; 33 } 34 return counts; 35 } 36 37 /** Previous / next sheet within the same category. */ 38 export function prevNext(items: Sheet[], current: Sheet): { prev?: Sheet; next?: Sheet } { 39 const i = items.findIndex((s) => s.id === current.id); 40 return { prev: i > 0 ? items[i - 1] : undefined, next: i >= 0 && i < items.length - 1 ? items[i + 1] : undefined }; 41 } 42 43 /** Distinct tags with usage counts, most-used first. */ 44 export async function allTags(): Promise<{ tag: string; count: number }[]> { 45 const sheets = await allSheets(); 46 const map = new Map<string, number>(); 47 for (const s of sheets) for (const t of s.data.tags) map.set(t, (map.get(t) ?? 0) + 1); 48 return [...map.entries()].map(([tag, count]) => ({ tag, count })).sort((a, b) => b.count - a.count || a.tag.localeCompare(b.tag)); 49 } 50 51 export async function allTools(): Promise<{ tool: string; count: number }[]> { 52 const sheets = await allSheets(); 53 const map = new Map<string, number>(); 54 for (const s of sheets) for (const t of s.data.tools) map.set(t, (map.get(t) ?? 0) + 1); 55 return [...map.entries()].map(([tool, count]) => ({ tool, count })).sort((a, b) => b.count - a.count || a.tool.localeCompare(b.tool)); 56 } 57 58 export function tagSlug(tag: string): string { 59 return tag.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''); 60 }