import { escapeHtml, getGitHubUrl, getLastUpdatedHtml, } from "../utils"; import { renderEmptyStateHtml, renderSharedCardHtml } from "./card-render"; export interface RenderableSkillFile { name: string; path: string; } export interface RenderableSkill { id: string; title: string; description?: string; path: string; skillFile: string; category: string; hasAssets: boolean; assetCount: number; files: RenderableSkillFile[]; lastUpdated?: string | null; } export type SkillSortOption = "title" | "lastUpdated"; /** * Build the URL of a skill's dedicated detail page. */ export function getSkillDetailUrl(id: string): string { return `/skill/${id}/`; } export function sortSkills( items: T[], sort: SkillSortOption ): T[] { return [...items].sort((a, b) => { if (sort === "lastUpdated") { const dateA = a.lastUpdated ? new Date(a.lastUpdated).getTime() : 0; const dateB = b.lastUpdated ? new Date(b.lastUpdated).getTime() : 0; return dateB - dateA; } return a.title.localeCompare(b.title); }); } export function renderSkillsHtml(items: RenderableSkill[]): string { if (items.length === 0) { return renderEmptyStateHtml("No skills found", "No skills are available right now."); } return items .map((item) => { const metaHtml = ` ${ item.hasAssets ? `${item.assetCount} asset${ item.assetCount === 1 ? "" : "s" }` : "" } ${item.files.length} file${ item.files.length === 1 ? "" : "s" } ${getLastUpdatedHtml(item.lastUpdated)} `; const actionsHtml = ` GitHub `; return renderSharedCardHtml({ title: item.title, description: item.description || "No description", href: getSkillDetailUrl(item.id), articleAttributes: { "data-path": item.skillFile, "data-skill-id": item.id, }, metaHtml, actionsHtml, }); }) .join(""); }