From 95b5dc4dfcba73cd139ef4a3c25fcfa0d07548e9 Mon Sep 17 00:00:00 2001 From: devRaGonSa Date: Thu, 21 May 2026 21:51:57 +0200 Subject: [PATCH] fix: refine live killfeed screen and realtime stats --- frontend/assets/css/historico.css | 147 +++++++++++++++++++-------- frontend/assets/js/partida-actual.js | 90 +++++++++++----- 2 files changed, 167 insertions(+), 70 deletions(-) diff --git a/frontend/assets/css/historico.css b/frontend/assets/css/historico.css index 7a217b0..2d19c88 100644 --- a/frontend/assets/css/historico.css +++ b/frontend/assets/css/historico.css @@ -589,43 +589,84 @@ gap: 14px; } +.current-match-killfeed-screen { + position: relative; + width: min(100%, 760px); + min-height: 180px; + max-height: 520px; + padding: 10px; + overflow: hidden; + border: 1px solid rgba(183, 201, 125, 0.28); + border-radius: 6px; + background: + linear-gradient(180deg, rgba(183, 201, 125, 0.08), transparent 24%), + rgba(5, 8, 6, 0.92); + box-shadow: + inset 0 0 0 1px rgba(0, 0, 0, 0.44), + inset 0 18px 48px rgba(0, 0, 0, 0.24); +} + +.current-match-killfeed-screen::after { + position: absolute; + inset: 0; + z-index: 1; + border-radius: inherit; + background: repeating-linear-gradient( + 180deg, + rgba(255, 255, 255, 0.018) 0, + rgba(255, 255, 255, 0.018) 1px, + transparent 1px, + transparent 5px + ); + pointer-events: none; + content: ""; +} + .current-match-killfeed { + position: relative; + z-index: 2; display: grid; - gap: 10px; - max-height: 760px; - padding: 4px 0 0; + gap: 6px; + max-height: 500px; overflow: hidden; } .current-match-killfeed__row { display: grid; - grid-template-columns: minmax(0, 1fr) minmax(102px, 150px) minmax(0, 1fr) auto; + grid-template-columns: minmax(0, 1fr) minmax(92px, 124px) minmax(0, 1fr); align-items: center; - gap: 12px; - min-height: 56px; - padding: 12px 14px; + gap: 8px; + min-height: 48px; + padding: 6px 9px; overflow: hidden; - border: 1px solid rgba(159, 168, 141, 0.18); - border-left: 3px solid rgba(183, 201, 125, 0.34); - border-radius: 6px; + border: 1px solid rgba(159, 168, 141, 0.12); + border-left: 2px solid rgba(183, 201, 125, 0.46); + border-radius: 3px; color: var(--text); background: - linear-gradient(135deg, rgba(183, 201, 125, 0.08), transparent 44%), - rgba(14, 19, 12, 0.84); + linear-gradient(90deg, rgba(183, 201, 125, 0.07), transparent 40%), + rgba(15, 20, 13, 0.68); animation: current-match-killfeed-enter 180ms ease-out; } +.current-match-killfeed__row:first-child { + border-color: rgba(183, 201, 125, 0.28); + background: + linear-gradient(90deg, rgba(183, 201, 125, 0.14), transparent 46%), + rgba(20, 27, 17, 0.86); +} + .current-match-killfeed__row.is-teamkill { border-left-color: rgba(210, 182, 118, 0.64); background: - linear-gradient(135deg, rgba(210, 182, 118, 0.12), transparent 48%), - rgba(73, 49, 27, 0.42); + linear-gradient(90deg, rgba(210, 182, 118, 0.12), transparent 48%), + rgba(73, 49, 27, 0.32); } .current-match-killfeed__player { min-width: 0; overflow: hidden; - font-size: 0.94rem; + font-size: 0.88rem; line-height: 1.2; text-overflow: ellipsis; white-space: nowrap; @@ -641,35 +682,37 @@ .current-match-killfeed__weapon { display: grid; - grid-template-rows: 34px; + grid-template-rows: 25px auto; align-items: center; justify-content: center; - min-width: 102px; - min-height: 40px; - padding: 2px 8px; - border: 1px solid rgba(183, 201, 125, 0.24); - border-radius: 4px; + gap: 1px; + min-width: 92px; + min-height: 38px; + padding: 2px 5px; + border: 1px solid rgba(183, 201, 125, 0.18); + border-radius: 3px; color: var(--text); - background: rgba(7, 10, 7, 0.8); + background: rgba(7, 10, 7, 0.72); } .current-match-killfeed__weapon-icon { display: block; - width: min(100%, 116px); - height: 32px; + width: min(100%, 104px); + height: 24px; object-fit: contain; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.72)); } .current-match-killfeed__weapon-fallback { display: grid; - width: 32px; - height: 32px; + width: 24px; + height: 24px; + justify-self: center; place-items: center; border: 1px solid rgba(210, 182, 118, 0.3); - border-radius: 4px; + border-radius: 3px; color: var(--accent-warm); - font-size: 1rem; + font-size: 0.82rem; font-weight: 800; } @@ -678,20 +721,22 @@ } .current-match-killfeed__weapon em { - position: absolute; - width: 1px; - height: 1px; - margin: -1px; - padding: 0; + display: block; + max-width: 112px; overflow: hidden; - clip: rect(0, 0, 0, 0); + color: var(--muted); + font-size: 0.58rem; + font-style: normal; + line-height: 1.1; + text-align: center; + text-overflow: ellipsis; white-space: nowrap; - border: 0; } .current-match-killfeed__teamkill { display: inline-flex; align-items: center; + margin-left: 4px; min-height: 20px; padding: 0 5px; border: 1px solid rgba(210, 182, 118, 0.36); @@ -932,27 +977,39 @@ } .current-match-killfeed { - max-height: none; + max-height: 500px; } .current-match-killfeed__row { - grid-template-columns: minmax(0, 1fr) minmax(96px, 128px) minmax(0, 1fr); - } - - .current-match-killfeed__teamkill { - grid-column: 1 / -1; - justify-self: end; + grid-template-columns: minmax(0, 1fr) minmax(86px, 116px) minmax(0, 1fr); } } @media (max-width: 480px) { .current-match-killfeed__row { - grid-template-columns: 1fr; - gap: 8px; + grid-template-columns: minmax(0, 1fr) 82px minmax(0, 1fr); + gap: 5px; + padding-inline: 6px; } .current-match-killfeed__weapon { - justify-self: start; + min-width: 82px; + padding-inline: 3px; + } + + .current-match-killfeed__player { + display: -webkit-box; + overflow: hidden; + font-size: 0.78rem; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + text-overflow: ellipsis; + white-space: normal; + } + + .current-match-killfeed__teamkill { + min-height: 16px; + font-size: 0.54rem; } } diff --git a/frontend/assets/js/partida-actual.js b/frontend/assets/js/partida-actual.js index cd942f4..aa3ddb0 100644 --- a/frontend/assets/js/partida-actual.js +++ b/frontend/assets/js/partida-actual.js @@ -1,5 +1,6 @@ const CURRENT_MATCH_POLL_INTERVAL_MS = 30 * 1000; const CURRENT_MATCH_KILL_FEED_POLL_INTERVAL_MS = 1500; +const CURRENT_MATCH_PLAYER_STATS_POLL_INTERVAL_MS = 3000; const CURRENT_MATCH_SERVERS = Object.freeze({ "comunidad-hispana-01": "Comunidad Hispana #01", "comunidad-hispana-02": "Comunidad Hispana #02", @@ -13,10 +14,30 @@ const CURRENT_MATCH_WEAPONS = Object.freeze({ "m1 garand": { label: "M1 Garand", icon: "m1_garand.PNG" }, mp40: { label: "MP40", icon: "mp40.PNG" }, "m1a1 thompson": { label: "M1A1 Thompson", icon: "thompson.PNG" }, + "m1a1": { label: "M1A1 Thompson", icon: "thompson.PNG" }, thompson: { label: "M1A1 Thompson", icon: "thompson.PNG" }, "gewehr 43": { label: "Gewehr 43", icon: "gewehr.PNG" }, + "gewehr43": { label: "Gewehr 43", icon: "gewehr.PNG" }, g43: { label: "Gewehr 43", icon: "gewehr.PNG" }, mg42: { label: "MG42", icon: "mg42.PNG" }, + kar98k: { label: "Kar98k", icon: "kar98k.PNG" }, + kar98: { label: "Kar98k", icon: "kar98k.PNG" }, + stg44: { label: "StG 44", icon: "stg44.PNG" }, + "stg 44": { label: "StG 44", icon: "stg44.PNG" }, + bar: { label: "BAR", icon: "" }, + "m1919": { label: "M1919", icon: "browing_m1919.PNG" }, + "m1919 browning": { label: "M1919", icon: "browing_m1919.PNG" }, + "browning m1919": { label: "M1919", icon: "browing_m1919.PNG" }, + "m1 carbine": { label: "M1 Carbine", icon: "m1_carabine.PNG" }, + "m1 carabine": { label: "M1 Carbine", icon: "m1_carabine.PNG" }, + luger: { label: "Luger", icon: "luger_p08.PNG" }, + "luger p08": { label: "Luger", icon: "luger_p08.PNG" }, + colt: { label: "Colt", icon: "colt_1911.PNG" }, + "colt 1911": { label: "Colt", icon: "colt_1911.PNG" }, + "colt m1911": { label: "Colt", icon: "colt_1911.PNG" }, + "frag grenade": { label: "Frag Grenade", icon: "" }, + grenade: { label: "Frag Grenade", icon: "" }, + "smoke grenade": { label: "Smoke Grenade", icon: "" }, unknown: { label: "Arma desconocida", icon: "" }, }); @@ -48,19 +69,16 @@ document.addEventListener("DOMContentLoaded", () => { nodes.history.href = `./historico.html?server=${encodeURIComponent(serverSlug)}`; const killFeedState = initializeKillFeed(nodes); const playerStatsState = initializePlayerStats(nodes); - let matchRefreshInFlight = false; - const refreshMatchPanels = async () => { - if (matchRefreshInFlight) { + let currentMatchRefreshInFlight = false; + const refreshCurrentMatch = async () => { + if (currentMatchRefreshInFlight) { return; } - matchRefreshInFlight = true; + currentMatchRefreshInFlight = true; try { - await Promise.allSettled([ - loadCurrentMatch({ backendBaseUrl, serverSlug, nodes }), - loadPlayerStats({ backendBaseUrl, serverSlug, nodes, playerStatsState }), - ]); + await loadCurrentMatch({ backendBaseUrl, serverSlug, nodes }); } finally { - matchRefreshInFlight = false; + currentMatchRefreshInFlight = false; } }; @@ -77,14 +95,31 @@ document.addEventListener("DOMContentLoaded", () => { } }; - void refreshMatchPanels(); + let playerStatsRefreshInFlight = false; + const refreshPlayerStats = async () => { + if (playerStatsRefreshInFlight) { + return; + } + playerStatsRefreshInFlight = true; + try { + await loadPlayerStats({ backendBaseUrl, serverSlug, nodes, playerStatsState }); + } finally { + playerStatsRefreshInFlight = false; + } + }; + + void refreshCurrentMatch(); void refreshKillFeed(); + void refreshPlayerStats(); window.setInterval(() => { - void refreshMatchPanels(); + void refreshCurrentMatch(); }, CURRENT_MATCH_POLL_INTERVAL_MS); window.setInterval(() => { void refreshKillFeed(); }, CURRENT_MATCH_KILL_FEED_POLL_INTERVAL_MS); + window.setInterval(() => { + void refreshPlayerStats(); + }, CURRENT_MATCH_PLAYER_STATS_POLL_INTERVAL_MS); }); async function loadCurrentMatch({ backendBaseUrl, serverSlug, nodes }) { @@ -120,7 +155,11 @@ async function loadPlayerStats({ backendBaseUrl, serverSlug, nodes, playerStatsS ); renderPlayerStats(payload?.data || {}, nodes, playerStatsState); } catch (error) { - setState(nodes.playerStatsState, "No se pudieron actualizar las estadisticas en vivo.", true); + setState( + nodes.playerStatsState, + "Todavía no hay estadísticas fiables de jugadores para esta partida.", + true, + ); } } @@ -162,11 +201,9 @@ function initializeKillFeed(nodes) {

Cargando feed de combate...

-
+
+
+
`, ); } @@ -218,10 +255,10 @@ function renderKillFeed(data, nodes, state) { if (events.length === 0) { nodes.feedList.innerHTML = ""; state.visibleSignature = ""; - setState(nodes.feedState, formatKillFeedCoverage(data.scope)); + setState(nodes.feedState, "Todavía no se han detectado bajas en esta partida."); return; } - const visualEvents = [...events].reverse(); + const visualEvents = events; const visibleSignature = visualEvents.map((event) => event.event_id).join("|"); if (visibleSignature !== state.visibleSignature) { nodes.feedList.innerHTML = visualEvents.map(renderKillFeedRow).join(""); @@ -246,9 +283,13 @@ function renderKillFeedRow(event) { ? 'TK' : ""; return ` -
- +
+ ${escapeHtml(event.killer_name || "Jugador no disponible")} + ${teamkillBadge} ${escapeHtml(event.victim_name || "Objetivo no disponible")} - ${teamkillBadge}
`; } @@ -301,7 +341,7 @@ function renderPlayerStats(data, nodes, state) { nodes.playerStatsShell.hidden = true; setState( nodes.playerStatsState, - "Todavia no hay estadisticas fiables de jugadores para esta partida.", + "Todavía no hay estadísticas fiables de jugadores para esta partida.", ); return; } @@ -618,9 +658,9 @@ function formatKillFeedCoverage(scope) { return "Cobertura parcial desde AdminLog reciente."; } if (scope === "no-current-match-events") { - return "Sin bajas recientes asociadas a la partida actual."; + return "Todavía no se han detectado bajas en esta partida."; } - return "Todavia no se han detectado bajas en esta partida."; + return "Todavía no se han detectado bajas en esta partida."; } function normalizeLookupText(value) {