export function relativeTime(iso: string | null): string { if (!iso) return ""; const then = new Date(iso).getTime(); const secs = Math.max(0, (Date.now() - then) / 1000); const units: [number, string][] = [ [60, "s"], [3600, "min"], [86400, "h"], [604800, "d"], [2592000, "wk"], [31536000, "mo"], ]; if (secs < 60) return "just now"; for (let i = 0; i < units.length - 1; i++) { const [, label] = units[i]; const next = units[i + 1][0]; if (secs < next) { const v = Math.floor(secs / units[i][0]); return `${v} ${label} ago`; } } const years = Math.floor(secs / 31536000); if (years >= 1) return `${years} yr ago`; const months = Math.floor(secs / 2592000); return `${months} mo ago`; } export function formatDuration(sec: number | null): string { if (sec == null) return ""; const h = Math.floor(sec / 3600); const m = Math.floor((sec % 3600) / 60); const s = Math.floor(sec % 60); const pad = (n: number) => String(n).padStart(2, "0"); return h > 0 ? `${h}:${pad(m)}:${pad(s)}` : `${m}:${pad(s)}`; } export function formatViews(n: number | null): string { if (n == null) return ""; if (n >= 1e9) return `${(n / 1e9).toFixed(1).replace(/\.0$/, "")}B`; if (n >= 1e6) return `${(n / 1e6).toFixed(1).replace(/\.0$/, "")}M`; if (n >= 1e3) return `${(n / 1e3).toFixed(1).replace(/\.0$/, "")}K`; return String(n); }