Fix historical leaderboard labels, stats ranking table uniformity and publish Steam icon

This commit is contained in:
devRaGonSa
2026-06-11 13:26:13 +02:00
parent d50d800554
commit ab696ab25d
7 changed files with 209 additions and 43 deletions

View File

@@ -45,24 +45,32 @@ const LEADERBOARD_METRICS = Object.freeze([
key: "kills",
title: "Top kills",
valueHeading: "Kills",
ratioHeading: "Kills/partida",
ratioMode: "kills",
emptyMessage: "Sin datos historicos suficientes para mostrar este ranking de kills.",
},
{
key: "deaths",
title: "Top muertes",
valueHeading: "Muertes",
ratioHeading: "Muertes/partida",
ratioMode: "deaths",
emptyMessage: "Sin datos historicos suficientes para mostrar este ranking de muertes.",
},
{
key: "matches_over_100_kills",
title: "Top partidas con 100+ kills",
valueHeading: "Partidas 100+",
ratioHeading: null,
ratioMode: null,
emptyMessage: "Ningun jugador ha registrado partidas de 100+ kills en esta ventana.",
},
{
key: "support",
title: "Top puntos de soporte",
valueHeading: "Soporte",
ratioHeading: "Soporte/partida",
ratioMode: "support",
emptyMessage: "Sin datos historicos suficientes para mostrar este ranking de soporte.",
},
]);
@@ -94,6 +102,7 @@ document.addEventListener("DOMContentLoaded", () => {
const weeklyTableNode = document.getElementById("weekly-leaderboard-table");
const weeklyBodyNode = document.getElementById("weekly-leaderboard-body");
const weeklyValueHeadingNode = document.getElementById("weekly-leaderboard-value-heading");
const weeklyRatioHeadingNode = document.getElementById("weekly-leaderboard-ratio-heading");
const weeklyWindowNoteNode = document.getElementById("weekly-window-note");
const weeklySnapshotMetaNode = document.getElementById(
"weekly-leaderboard-snapshot-meta",
@@ -210,6 +219,7 @@ document.addEventListener("DOMContentLoaded", () => {
weeklyBodyNode,
weeklyTitleNode,
weeklyValueHeadingNode,
weeklyRatioHeadingNode,
weeklyWindowNoteNode,
weeklySnapshotMetaNode,
activeMetricConfig,
@@ -547,6 +557,7 @@ function hydrateWeeklyLeaderboard(
bodyNode,
titleNode,
valueHeadingNode,
ratioHeadingNode,
noteNode,
snapshotMetaNode,
metricConfig,
@@ -555,6 +566,7 @@ function hydrateWeeklyLeaderboard(
const targetServerSlug = result.value?.data?.server_slug || activeServerSlug;
const resolvedTimeframeKey = result.value?.data?.timeframe || timeframeKey;
valueHeadingNode.textContent = metricConfig.valueHeading;
syncLeaderboardRatioColumn(tableNode, ratioHeadingNode, bodyNode, metricConfig);
if (result.status !== "fulfilled") {
titleNode.textContent = buildLeaderboardTitle(
metricConfig,
@@ -614,13 +626,11 @@ function hydrateWeeklyLeaderboard(
bodyNode.innerHTML = items
.map(
(item) => {
const kills = resolveHistoricalKills(item, metricConfig);
const matches = Number(item.matches_considered);
const killsPerMatch = formatHistoricalKillsPerMatch(
item?.kills_per_match,
kills,
matches,
);
const ratioValue = formatHistoricalRatio(item, metricConfig, matches);
const ratioCell = metricConfig.ratioMode
? `<td>${escapeHtml(ratioValue)}</td>`
: "";
return `
<tr>
@@ -628,13 +638,14 @@ function hydrateWeeklyLeaderboard(
<td>${escapeHtml(item.player?.name || "Jugador no identificado")}</td>
<td>${escapeHtml(formatNumber(item.metric_value))}</td>
<td>${escapeHtml(formatNumber(item.matches_considered))}</td>
<td>${escapeHtml(killsPerMatch)}</td>
${ratioCell}
</tr>
`;
},
)
.join("");
stateNode.hidden = true;
syncLeaderboardRatioColumn(tableNode, ratioHeadingNode, bodyNode, metricConfig);
tableNode.hidden = false;
}
@@ -1724,13 +1735,43 @@ function resolveHistoricalKills(item, metricConfig) {
return Number.NaN;
}
function formatHistoricalKillsPerMatch(rawKillsPerMatch, rawKills, rawMatches) {
const directValue = Number(rawKillsPerMatch);
function syncLeaderboardRatioColumn(tableNode, ratioHeadingNode, bodyNode, metricConfig) {
if (!tableNode || !ratioHeadingNode || !bodyNode) {
return;
}
const showRatio = Boolean(metricConfig?.ratioMode);
ratioHeadingNode.hidden = !showRatio;
ratioHeadingNode.textContent = metricConfig?.ratioHeading || "";
const ratioColumnIndex = ratioHeadingNode.cellIndex;
bodyNode.querySelectorAll("tr").forEach((row) => {
const ratioCell = row.children[ratioColumnIndex];
if (ratioCell) {
ratioCell.hidden = !showRatio;
}
});
}
function formatHistoricalRatio(item, metricConfig, matches) {
if (!metricConfig?.ratioMode) {
return "";
}
if (metricConfig.ratioMode === "kills") {
const kills = resolveHistoricalKills(item, metricConfig);
return formatHistoricalPerMatch(item?.kills_per_match, kills, matches);
}
if (metricConfig.ratioMode === "deaths" || metricConfig.ratioMode === "support") {
return formatHistoricalPerMatch(null, Number(item?.metric_value), matches);
}
return "";
}
function formatHistoricalPerMatch(rawDirectValue, rawTotalValue, rawMatches) {
const directValue = Number(rawDirectValue);
if (Number.isFinite(directValue)) {
return formatDecimal(directValue, 2);
}
const kills = Number(rawKills);
const kills = Number(rawTotalValue);
const matches = Number(rawMatches);
if (!Number.isFinite(kills) || !Number.isFinite(matches) || matches <= 0) {
return "-";

View File

@@ -271,7 +271,7 @@
if (statusCode === 400 && normalizedMessage.includes("metric")) {
setRankingState("warning", "La m\u00e9trica solicitada no est\u00e1 soportada.");
renderEmptyState(
"Usa kills, deaths, teamkills, partidas jugadas, K/D o Kills/partida.",
"Usa Kills, Muertes, TK, Partidas, KD o Kills/partida.",
);
return;
}
@@ -397,10 +397,10 @@
</div>
</td>
<td class="ranking-table__metric">${formatMetricValue(item.metric_value, metric)}</td>
<td>${safeInt(item.matches_considered, 0)}</td>
<td>${safeInt(item.kills, 0)}</td>
<td>${safeInt(item.deaths, 0)}</td>
<td>${safeInt(item.teamkills, 0)}</td>
<td>${safeInt(item.matches_considered, 0)}</td>
<td>${safeDecimal(item.kd_ratio, 2, "0.00")}</td>
${hideKppColumn ? "" : `<td>${killsPerMatch}</td>`}
</tr>
@@ -454,10 +454,10 @@
function labelForMetric(metric) {
const labels = {
kills: "Kills",
deaths: "Deaths",
teamkills: "Teamkills",
matches_considered: "Partidas jugadas",
kd_ratio: "K/D",
deaths: "Muertes",
teamkills: "TK",
matches_considered: "Partidas",
kd_ratio: "KD",
kills_per_match: "Kills/partida",
};
return labels[metric] || "Kills";

View File

@@ -359,8 +359,8 @@
.map((item) => {
const rank = safeInt(item.ranking_position, 0);
const playerName = escapeHtml(String(item.player_name || "Jugador sin nombre"));
const kills = safeInt(firstFiniteValue(item.kills, item.metric_value), 0);
const matches = safeInt(item.matches_considered, 0);
const kills = safeInt(firstFiniteValue(item.kills, item.metric_value), 0);
const killsPerMatch = formatKillsPerMatch(
item.kills_per_match,
kills,
@@ -378,12 +378,12 @@
<strong>${playerName}</strong>
</div>
</td>
<td class="stats-annual-metric">${kills}</td>
<td>${matches}</td>
<td>${killsPerMatch}</td>
<td class="stats-annual-metric">${kills}</td>
<td>${deaths}</td>
<td>${teamkills}</td>
<td>${kd}</td>
<td>${killsPerMatch}</td>
</tr>
`;
})
@@ -396,12 +396,12 @@
<tr>
<th>Posici\u00f3n</th>
<th>Jugador</th>
<th>Kills</th>
<th>Partidas</th>
<th>Kills/partida</th>
<th>Kills</th>
<th>Muertes</th>
<th>Teamkills</th>
<th>K/D</th>
<th>TK</th>
<th>KD</th>
<th>Kills/partida</th>
</tr>
</thead>
<tbody>${rowsMarkup}</tbody>
@@ -574,8 +574,8 @@
<article class="stats-summary-card">
<p class="stats-summary-title">Ventana semanal</p>
<p><strong>Kills:</strong> ${safeInt(weeklyData?.kills, 0)}</p>
<p><strong>Deaths:</strong> ${safeInt(weeklyData?.deaths, 0)}</p>
<p><strong>Teamkills:</strong> ${safeInt(weeklyData?.teamkills, 0)}</p>
<p><strong>Muertes:</strong> ${safeInt(weeklyData?.deaths, 0)}</p>
<p><strong>TK:</strong> ${safeInt(weeklyData?.teamkills, 0)}</p>
</article>
`;
@@ -590,8 +590,8 @@
<article class="stats-summary-card">
<p class="stats-summary-title">Ventana mensual</p>
<p><strong>Kills:</strong> ${safeInt(monthlyData?.kills, 0)}</p>
<p><strong>Deaths:</strong> ${safeInt(monthlyData?.deaths, 0)}</p>
<p><strong>Teamkills:</strong> ${safeInt(monthlyData?.teamkills, 0)}</p>
<p><strong>Muertes:</strong> ${safeInt(monthlyData?.deaths, 0)}</p>
<p><strong>TK:</strong> ${safeInt(monthlyData?.teamkills, 0)}</p>
</article>
`;
@@ -697,16 +697,16 @@
<span class="stats-comparison-card__metric-value">${kills}</span>
</div>
<div class="stats-comparison-card__metric">
<span class="stats-comparison-card__metric-label">Deaths</span>
<span class="stats-comparison-card__metric-label">Muertes</span>
<span class="stats-comparison-card__metric-value">${deaths}</span>
</div>
<div class="stats-comparison-card__metric">
<span class="stats-comparison-card__metric-label">K/D</span>
<span class="stats-comparison-card__metric-label">KD</span>
<span class="stats-comparison-card__metric-value">${kdRatio}</span>
</div>
</div>
<p class="stats-comparison-card__detail">
<strong>Kills por partida:</strong> ${killsPerMatch}
<strong>Kills/partida:</strong> ${killsPerMatch}
</p>
<p class="stats-comparison-card__note">${escapeHtml(rankingState.detail)}</p>
</article>
@@ -739,11 +739,11 @@
<span class="stats-comparison-card__metric-value">${safeDecimal(monthlyKillsPerMatch, 2, "0.00")}</span>
</div>
<div class="stats-comparison-card__metric">
<span class="stats-comparison-card__metric-label">K/D semanal</span>
<span class="stats-comparison-card__metric-label">KD semanal</span>
<span class="stats-comparison-card__metric-value">${safeDecimal(weeklyKd, 2, "0.00")}</span>
</div>
<div class="stats-comparison-card__metric">
<span class="stats-comparison-card__metric-label">K/D mensual</span>
<span class="stats-comparison-card__metric-label">KD mensual</span>
<span class="stats-comparison-card__metric-value">${safeDecimal(monthlyKd, 2, "0.00")}</span>
</div>
</div>
@@ -775,7 +775,7 @@
}
const rank = safeInt(ranking.ranking_position, 0);
const metric = escapeHtml(String(ranking.metric || annualMetric));
const metric = escapeHtml(labelForStatsMetric(ranking.metric || annualMetric));
return `
<p><strong>Posici\u00f3n:</strong> ${rank}</p>
@@ -863,6 +863,18 @@
return `Ventana: ${windowStart} - ${windowEnd}`;
}
function labelForStatsMetric(metric) {
const labels = {
kills: "Kills",
deaths: "Muertes",
teamkills: "TK",
matches_considered: "Partidas",
kd_ratio: "KD",
kills_per_match: "Kills/partida",
};
return labels[String(metric || "").trim()] || "Kills";
}
function safeInt(value, fallback = 0) {
const parsed = Number(value);
if (!Number.isFinite(parsed)) {