further changes to backend for adjusting points, showing timestamps, and how categories are listed. uploaded build of react and actual frontend source
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
const number = new Intl.NumberFormat("en-US");
|
||||
|
||||
/** 12.345 -> "12.345", 83.2 -> "1:23.200", 3723.5 -> "1:02:03.500". */
|
||||
export function formatTime(seconds: number): string {
|
||||
const ms = Math.round(seconds * 1000);
|
||||
const h = Math.floor(ms / 3_600_000);
|
||||
const m = Math.floor((ms % 3_600_000) / 60_000);
|
||||
const s = Math.floor((ms % 60_000) / 1000);
|
||||
const rest = String(ms % 1000).padStart(3, "0");
|
||||
if (h > 0) return `${h}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}.${rest}`;
|
||||
if (m > 0) return `${m}:${String(s).padStart(2, "0")}.${rest}`;
|
||||
return `${s}.${rest}`;
|
||||
}
|
||||
|
||||
/** Signed difference, e.g. "+1.204" or "−0.500". */
|
||||
export function formatDelta(seconds: number): string {
|
||||
const sign = seconds < 0 ? "−" : "+";
|
||||
return sign + formatTime(Math.abs(seconds));
|
||||
}
|
||||
|
||||
export function formatNumber(n: number): string {
|
||||
return number.format(n);
|
||||
}
|
||||
|
||||
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
|
||||
const UNITS: [Intl.RelativeTimeFormatUnit, number][] = [
|
||||
["year", 31_536_000],
|
||||
["month", 2_592_000],
|
||||
["week", 604_800],
|
||||
["day", 86_400],
|
||||
["hour", 3_600],
|
||||
["minute", 60],
|
||||
];
|
||||
|
||||
/** Unix seconds -> "3 weeks ago". */
|
||||
export function timeAgo(unixSeconds: number, now = Date.now() / 1000): string {
|
||||
// Never show "in 3 minutes" when a server clock is slightly ahead.
|
||||
const diff = Math.min(0, unixSeconds - now);
|
||||
for (const [unit, size] of UNITS) {
|
||||
if (Math.abs(diff) >= size) return rtf.format(Math.round(diff / size), unit);
|
||||
}
|
||||
return "just now";
|
||||
}
|
||||
|
||||
/** Unix seconds -> "27 Sep 2026, 14:03:09" in the viewer's own time zone. */
|
||||
export function formatDate(unixSeconds: number): string {
|
||||
return new Date(unixSeconds * 1000).toLocaleString("en-GB", {
|
||||
day: "numeric",
|
||||
month: "short",
|
||||
year: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
hour12: false,
|
||||
});
|
||||
}
|
||||
|
||||
export function serverLabel(tag: string): string {
|
||||
return tag.toUpperCase();
|
||||
}
|
||||
|
||||
/** Which bonus band a position is in, for the label next to the multiplier. */
|
||||
export function bonusLabel(position: number, completions: number): string | null {
|
||||
if (completions < 100) return null;
|
||||
const x = (position - 1) / completions;
|
||||
if (x < 0.01) return "Top 1%";
|
||||
if (x < 0.05) return "Top 5%";
|
||||
return null;
|
||||
}
|
||||
|
||||
/** How many players on a board get points (half from 200 completions on). */
|
||||
export function pointedCount(completions: number): number {
|
||||
return completions < 200 ? completions : Math.floor(completions / 2);
|
||||
}
|
||||
Reference in New Issue
Block a user