This commit is contained in:
2026-10-21 14:02:50 -04:00
parent 69d49073f0
commit 613647cb50
6 changed files with 580 additions and 22 deletions
+61 -1
View File
@@ -218,6 +218,7 @@ function renderSections() {
const available = {
"account-section": true,
"leaderboard-section": true,
"seasons-section": true,
"chat-section": true,
"alerts-section": true,
"stats-section": statsLoaded,
@@ -251,6 +252,7 @@ $("section-nav").addEventListener("click", (event) => {
if (selectedSection === "account-section") loadMe();
if (selectedSection === "leaderboard-section") loadLeaderboard();
if (selectedSection === "chat-section") loadChat();
if (selectedSection === "seasons-section") loadSeasons();
syncPresence();
});
@@ -387,8 +389,20 @@ async function refreshState() {
const t0 = Date.now();
const s = await api("GET", "/api/state");
const first = !game;
const changedSeason = game && game.season?.id !== s.season?.id;
if (changedSeason) {
statsLoaded = false;
currentShareText = "";
alertObservation = null;
$("press-result").textContent = "";
$("me-section").hidden = true;
}
clockOffset = s.now - (t0 + Date.now()) / 2;
game = s;
if (s.season) {
$("season-subtitle").textContent = s.season.name;
$("season-label").textContent = `${s.ended ? "Season finished. " : ""}Next season: ${new Date(s.season.ends_at).toISOString().slice(0, 10)} UTC.`;
}
observeZoneAlerts(s);
$("history-global-summary").textContent =
`There have been ${s.total_presses.toLocaleString()} total presses and there are ${s.total_players.toLocaleString()} total players.`;
@@ -399,6 +413,7 @@ async function refreshState() {
await loadLeaderboard();
if (selectedSection === "chat-section") await loadChat();
if (selectedSection === "account-section") await loadMe();
if (selectedSection === "seasons-section") await loadSeasons();
}
function updateButton() {
@@ -417,7 +432,7 @@ function tick() {
cd.textContent = formatMs(remaining);
setZoneClass(cd, zone.name);
setZoneClass($("the-button"), zone.name);
$("zone-label").textContent = game.ended ? "game over" : `${zone.name} zone \u00b7 ${zone.points} pt${zone.points === 1 ? "" : "s"}`;
$("zone-label").textContent = game.ended ? "season finished" : `${zone.name} zone \u00b7 ${zone.points} pt${zone.points === 1 ? "" : "s"}`;
const pct = Math.min(100, Math.max(0, ((game.duration_ms - remaining) / game.duration_ms) * 100));
$("zone-marker").style.left = `${pct}%`;
if (!game.ended && remaining <= 0) refreshState().catch(() => {});
@@ -513,6 +528,49 @@ async function loadMe() {
}
}
function seasonDuration(ms) {
const days = Math.floor(ms / 86400000);
return `${days ? `${days}d ` : ""}${formatMs(ms % 86400000).slice(0, -3)}`;
}
async function loadSeasons() {
try {
const result = await api("GET", "/api/seasons");
const current = result.current;
$("season-current").replaceChildren(
el("p", "CURRENT SEASON", "eyebrow"), el("h3", current.name),
el("p", `${current.ended ? "Finished - next countdown" : "Next season"}: ${new Date(current.ends_at).toISOString().slice(0, 10)} at 00:00 UTC`, "fine-print"),
);
$("seasons-status").textContent = result.seasons.length ? "" : "No finished seasons yet. This chapter is still being written.";
$("season-winners").hidden = result.seasons.length === 0;
fillTable($("season-winners"), ["Season", "Winner(s)", "Points each", "Lasted"], result.seasons.map((season) => [
season.name, season.winners.map((p) => p.name).join(", ") || "No winner (no presses)",
season.winners.length ? season.winners[0].total_points.toLocaleString() : "--", seasonDuration(season.duration_ms),
]));
const container = $("season-standings");
// Do not replace focused/open archive details on every poll.
const signature = JSON.stringify(result.seasons);
if (container.dataset.signature !== signature) {
container.dataset.signature = signature;
container.replaceChildren(...result.seasons.map((season) => {
const details = el("details");
details.append(el("summary", `${season.name} - final standings`));
details.append(el("p", `Played from ${new Date(season.played_from).toLocaleString()} until ${new Date(season.finished_at).toLocaleString()}. Ended by ${season.reason === "boundary" ? "the next season" : "the countdown"}.`, "fine-print"));
const wrapper = el("div", undefined, "table-scroll");
const table = el("table");
fillTable(table, ["#", "Player", "Points", "Presses"], season.leaderboard.map((player, index) => [
index + 1, player.name, player.total_points.toLocaleString(), player.press_count.toLocaleString(),
]));
wrapper.append(table);
details.append(wrapper);
return details;
}));
}
} catch {
$("seasons-status").textContent = "Seasons could not be refreshed. Retrying automatically...";
}
}
async function loadLeaderboard() {
try {
const { leaderboard } = await api("GET", "/api/leaderboard");
@@ -592,8 +650,10 @@ $("chat-form").addEventListener("submit", async (event) => {
});
async function loadStats() {
const seasonId = game?.season?.id;
try {
const s = await api("GET", "/api/stats");
if (game?.season?.id !== seasonId) return;
statsLoaded = true;
renderSections();
const summary = $("stats-summary");