export function fmtInt(v) {
const n = Number(v);
return Number.isFinite(n) ? n.toLocaleString("en-US") : String(v ?? "");
}
export function fmtDuration(secs) {
const s = Number(secs);
if (!Number.isFinite(s)) return "—";
if (s < 1) return `${s.toFixed(1)}s`;
const t = Math.round(s);
const h = Math.floor(t / 3600);
const m = Math.floor((t % 3600) / 60);
const sec = t % 60;
if (h) return `${h}h${m}m`;
if (m) return `${m}m${sec}s`;
return `${sec}s`;
}
export function fmtCompact(v) {
const n = Number(v);
if (!Number.isFinite(n)) return String(v ?? "");
const abs = Math.abs(n);
if (abs < 1000) return String(n);
const units = [
[1e9, "B"],
[1e6, "M"],
[1e3, "K"],
];
for (const [base, suf] of units) {
if (abs >= base) {
const val = n / base;
let str = val.toFixed(val >= 100 ? 0 : val >= 10 ? 1 : 2);
if (str.includes(".")) str = str.replace(/0+$/, "").replace(/\.$/, "");
return `${str}${suf}`;
}
}
return String(n);
}
export function escapeHtml(s) {
return String(s ?? "").replace(
/[&<>"]/g,
(c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c],
);
}
export function mdInline(s) {
return escapeHtml(s)
.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>")
.replace(/`([^`]+)`/g, "<code>$1</code>");
}