Display Formatters
Pure presentation helpers: clockMMSS, pct, surname, ordinal, luminance/inkOn (readable ink over a colour), rgba/hex. No domain logic.
// Generic display formatters (isomorphic). No domain logic — pure presentation.
/** Seconds → "M:SS" (clock). */
export const clockMMSS = (secs: number): string => {
const s = Math.max(0, Math.floor(secs));
return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`;
};
/** 0..1 (or 0..100) → "NN%". Pass `of100` when the input is already a percentage. */
export const pct = (v: number, digits = 0, of100 = false): string =>
`${(of100 ? v : v * 100).toFixed(digits)}%`;
/** Last token of a full name ("Vinícius Júnior" → "Júnior"). */
export const surname = (name?: string | null): string => {
const p = (name || "").trim().split(/\s+/);
return p.length > 1 ? p[p.length - 1] : name || "";
};
/** Ordinal suffix ("1st", "2nd", "3rd", "11th"). */
export const ordinal = (n: number): string => {
const s = ["th", "st", "nd", "rd"];
const v = n % 100;
return n + (s[(v - 20) % 10] || s[v] || s[0]);
};
/** HTML-escape for values interpolated into raw SVG/markup strings. */
export const esc = (s?: string | null): string =>
(s || "").replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
/** Relative luminance of a hex colour (0..1). */
export const luminance = (hex?: string | null): number => {
if (!hex) return 0;
const h = hex.replace("#", "");
if (h.length < 6) return 0;
return (
(0.299 * parseInt(h.slice(0, 2), 16) +
0.587 * parseInt(h.slice(2, 4), 16) +
0.114 * parseInt(h.slice(4, 6), 16)) /
255
);
};
/** Readable ink (#08080A / #fff) over a given background hex. */
export const inkOn = (hex?: string | null): string => (luminance(hex) > 0.6 ? "#08080A" : "#FFFFFF");
/** hex → "rgba(r,g,b,a)". */
export const rgba = (hex: string, a: number): string => {
const h = (hex || "").replace("#", "");
return `rgba(${parseInt(h.slice(0, 2), 16)},${parseInt(h.slice(2, 4), 16)},${parseInt(h.slice(4, 6), 16)},${a})`;
};
/** Normalize a colour to a leading-# hex, or null. */
export const hex = (c?: string | null): string | null =>
c ? (c.startsWith("#") ? c : "#" + c) : null;