2026-06-01 08:40:23 +02:00

92 lines
2.9 KiB
JavaScript

// leaderboard.js - leaderboard page logic
import { getLeaderboard } from "./api.js";
import { getLobbyName, getPlayerName } from "./storage.js";
document.addEventListener("DOMContentLoaded", () => {
const currentPlayer = getPlayerName();
const body = document.getElementById("lb-body");
/**
* Escape HTML special characters to prevent XSS.
* @param {string} str - Raw user-provided string.
* @returns {string} HTML-safe string.
*/
function escHtml(str) {
return String(str)
.replace(/&/g, "&")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;");
}
/** Render the leaderboard from backend data. */
async function render() {
const lobbyName = getLobbyName();
let board = [];
try {
const data = await getLeaderboard(lobbyName);
board = data.leaderboard || [];
} catch (_error) {
body.innerHTML = `
<div class="lb-empty">
<p class="lb-empty__text">Could not load the leaderboard. Make sure the backend is running.</p>
<a href="lobby.html" class="btn btn--primary btn--sm">Back to lobby</a>
</div>`;
return;
}
body.innerHTML = "";
if (!board.length) {
body.innerHTML = `
<div class="lb-empty">
<div class="lb-empty__icon">🏁</div>
<p class="lb-empty__text">No games played yet. Be the first on the board!</p>
<a href="lobby.html" class="btn btn--primary btn--sm">Play now →</a>
</div>`;
return;
}
const medals = ["🥇", "🥈", "🥉"];
const scoreClasses = ["gold", "silver", "bronze"];
board.forEach((entry, index) => {
const rank = index + 1;
const playerName = entry.playerName || entry.name || "Anonymous";
const isYou = playerName === currentPlayer;
const date = entry.date
? new Date(entry.date).toLocaleDateString("en-CH", {
day: "2-digit",
month: "short",
})
: "—";
const rounds = (entry.scores || []).join(" · ") || "—";
const row = document.createElement("div");
row.className = `lb-row${rank <= 3 ? ` rank-${rank}` : ""}`;
row.style.animationDelay = `${index * 0.05}s`;
row.innerHTML = `
<span class="lb-rank">${rank <= 3 ? `<span class="lb-medal">${medals[rank - 1]}</span>` : rank}</span>
<span class="lb-name${isYou ? " is-you" : ""}">${escHtml(playerName)}</span>
<span class="lb-rounds hide-sm">${escHtml(rounds)}</span>
<span class="lb-date hide-sm">${date}</span>
<span class="lb-score${rank <= 3 ? ` ${scoreClasses[rank - 1]}` : ""}">${entry.totalScore}</span>
`;
body.appendChild(row);
});
const latest = board.find(
(entry) => (entry.playerName || entry.name) === currentPlayer,
);
if (latest) {
document.getElementById("your-bar").style.display = "flex";
document.getElementById("your-bar-name").textContent =
latest.playerName || latest.name;
document.getElementById("your-bar-score").textContent = latest.totalScore;
}
}
render();
});