siftlode/frontend/src/lib/format.ts
npeter83 e56502789f feat: M4 (part 2) — React reader UI with theming
- Vite + React + TS + Tailwind SPA served by FastAPI (multi-stage Docker build)
- Four color schemes (Midnight default, Forest, Slate, YouTube) x dark/light,
  adjustable text size; persisted to user preferences and localStorage
- Header search, grid/list toggle, theme menu; sidebar filters (show state,
  sort, include Shorts/live, language + topic tag chips with any/all matching)
- Infinite-scroll feed of video cards; click opens youtube.com in a new tab;
  per-video watched / saved / hidden actions with optimistic updates
- SPA fallback routing; login screen for unauthenticated users
2026-06-11 02:19:47 +02:00

43 lines
1.4 KiB
TypeScript

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);
}