spb/autoscholar
Public
1import { DISCIPLINE_LABELS, RESEARCH_MODE_LABELS } from "@autoscholar/schemas";23export function fmtDate(4 d: string | Date | null | undefined,5 opts: Intl.DateTimeFormatOptions = { year: "numeric", month: "long", day: "numeric" },6): string {7 if (!d) return "—";8 return new Intl.DateTimeFormat("en-CA", { timeZone: "UTC", ...opts }).format(new Date(d));9}10export function fmtDateTime(d: string | Date | null | undefined): string {11 if (!d) return "—";12 return new Intl.DateTimeFormat("en-CA", {13 year: "numeric",14 month: "short",15 day: "numeric",16 hour: "2-digit",17 minute: "2-digit",18 second: "2-digit",19 hour12: false,20 }).format(new Date(d));21}22export function ago(d: string | Date | null | undefined): string {23 if (!d) return "never";24 const s = Math.max(0, (Date.now() - new Date(d).getTime()) / 1000);25 if (s < 60) return `${Math.round(s)}s ago`;26 if (s < 3600) return `${Math.round(s / 60)}m ago`;27 if (s < 86400) return `${Math.round(s / 3600)}h ago`;28 return `${Math.round(s / 86400)}d ago`;29}30export function fmtBytes(n: number): string {31 if (n < 1024) return `${n} B`;32 if (n < 1024 ** 2) return `${(n / 1024).toFixed(1)} KB`;33 if (n < 1024 ** 3) return `${(n / 1024 ** 2).toFixed(1)} MB`;34 return `${(n / 1024 ** 3).toFixed(2)} GB`;35}36export function fmtUsd(n: number | string | null | undefined): string {37 return `$${Number(n ?? 0).toFixed(2)}`;38}39export function disciplineLabel(d: string): string {40 return (DISCIPLINE_LABELS as Record<string, string>)[d] ?? d;41}42export function modeLabel(m: string): string {43 return (RESEARCH_MODE_LABELS as Record<string, string>)[m] ?? m;44}45export function shortHash(h: string | null | undefined, n = 12): string {46 return h ? h.slice(0, n) : "—";47}48