fix: refine two-column live combat feed
This commit is contained in:
@@ -591,16 +591,16 @@
|
|||||||
|
|
||||||
.current-match-killfeed-screen {
|
.current-match-killfeed-screen {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: min(100%, 760px);
|
width: 100%;
|
||||||
min-height: 180px;
|
min-height: 180px;
|
||||||
max-height: 520px;
|
max-height: 520px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid rgba(183, 201, 125, 0.28);
|
border: 1px solid rgba(159, 168, 141, 0.2);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background:
|
background:
|
||||||
linear-gradient(180deg, rgba(183, 201, 125, 0.08), transparent 24%),
|
linear-gradient(180deg, rgba(255, 255, 255, 0.035), transparent 24%),
|
||||||
rgba(5, 8, 6, 0.92);
|
rgba(7, 9, 9, 0.94);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
inset 0 0 0 1px rgba(0, 0, 0, 0.44),
|
inset 0 0 0 1px rgba(0, 0, 0, 0.44),
|
||||||
inset 0 18px 48px rgba(0, 0, 0, 0.24);
|
inset 0 18px 48px rgba(0, 0, 0, 0.24);
|
||||||
@@ -626,34 +626,41 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 6px;
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
align-items: start;
|
||||||
|
gap: 8px;
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.current-match-killfeed__column {
|
||||||
|
display: grid;
|
||||||
|
align-content: start;
|
||||||
|
gap: 6px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.current-match-killfeed__row {
|
.current-match-killfeed__row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1fr) minmax(92px, 124px) minmax(0, 1fr);
|
grid-template-columns: minmax(0, 1fr) minmax(86px, 112px) minmax(0, 1fr);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
min-height: 48px;
|
min-height: 54px;
|
||||||
padding: 6px 9px;
|
padding: 6px 9px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid rgba(159, 168, 141, 0.12);
|
border: 1px solid rgba(159, 168, 141, 0.14);
|
||||||
border-left: 2px solid rgba(183, 201, 125, 0.46);
|
border-left: 2px solid rgba(159, 168, 141, 0.24);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
background:
|
background: rgba(19, 22, 22, 0.78);
|
||||||
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;
|
animation: current-match-killfeed-enter 180ms ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-match-killfeed__row:first-child {
|
.current-match-killfeed__column:last-child .current-match-killfeed__row:last-child {
|
||||||
border-color: rgba(183, 201, 125, 0.28);
|
border-color: rgba(210, 182, 118, 0.22);
|
||||||
background:
|
background:
|
||||||
linear-gradient(90deg, rgba(183, 201, 125, 0.14), transparent 46%),
|
linear-gradient(90deg, rgba(210, 182, 118, 0.08), transparent 46%),
|
||||||
rgba(20, 27, 17, 0.86);
|
rgba(24, 25, 22, 0.92);
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-match-killfeed__row.is-teamkill {
|
.current-match-killfeed__row.is-teamkill {
|
||||||
@@ -664,22 +671,36 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.current-match-killfeed__player {
|
.current-match-killfeed__player {
|
||||||
|
display: grid;
|
||||||
|
align-content: center;
|
||||||
|
gap: 3px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: hidden;
|
|
||||||
font-size: 0.88rem;
|
font-size: 0.88rem;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-match-killfeed__player-name {
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-match-killfeed__player--killer {
|
.current-match-killfeed__player--killer {
|
||||||
color: var(--accent-strong);
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-match-killfeed__player--victim {
|
.current-match-killfeed__player--victim {
|
||||||
color: var(--text-soft);
|
color: var(--text-soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.current-match-killfeed__player-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.current-match-killfeed__weapon {
|
.current-match-killfeed__weapon {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 25px auto;
|
grid-template-rows: 25px auto;
|
||||||
@@ -689,10 +710,10 @@
|
|||||||
min-width: 92px;
|
min-width: 92px;
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
padding: 2px 5px;
|
padding: 2px 5px;
|
||||||
border: 1px solid rgba(183, 201, 125, 0.18);
|
border: 1px solid rgba(159, 168, 141, 0.18);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
background: rgba(7, 10, 7, 0.72);
|
background: rgba(8, 10, 11, 0.74);
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-match-killfeed__weapon-icon {
|
.current-match-killfeed__weapon-icon {
|
||||||
@@ -733,19 +754,59 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.current-match-killfeed__team-badge,
|
||||||
.current-match-killfeed__teamkill {
|
.current-match-killfeed__teamkill {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-left: 4px;
|
justify-content: center;
|
||||||
min-height: 20px;
|
min-height: 18px;
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
border: 1px solid rgba(210, 182, 118, 0.36);
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
color: var(--accent-warm);
|
|
||||||
font-size: 0.62rem;
|
font-size: 0.62rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.current-match-killfeed__team-badge {
|
||||||
|
border: 1px solid rgba(159, 168, 141, 0.2);
|
||||||
|
color: var(--text-soft);
|
||||||
|
background: rgba(159, 168, 141, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-match-killfeed__team-badge--allies {
|
||||||
|
border-color: rgba(100, 139, 178, 0.34);
|
||||||
|
color: rgba(192, 215, 238, 0.96);
|
||||||
|
background: rgba(67, 101, 137, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-match-killfeed__team-badge--axis {
|
||||||
|
border-color: rgba(167, 109, 96, 0.36);
|
||||||
|
color: rgba(231, 198, 190, 0.96);
|
||||||
|
background: rgba(116, 68, 58, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-match-killfeed__team-badge--unknown {
|
||||||
|
border-color: rgba(159, 168, 141, 0.22);
|
||||||
|
color: var(--muted);
|
||||||
|
background: rgba(159, 168, 141, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-match-killfeed__teamkill {
|
||||||
|
border: 1px solid rgba(210, 182, 118, 0.36);
|
||||||
|
color: var(--accent-warm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-match-player-count {
|
||||||
|
width: fit-content;
|
||||||
|
margin: -6px 0 16px;
|
||||||
|
padding: 7px 10px;
|
||||||
|
border: 1px solid rgba(159, 168, 141, 0.16);
|
||||||
|
border-radius: 6px;
|
||||||
|
color: var(--text-soft);
|
||||||
|
background: rgba(14, 17, 18, 0.7);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes current-match-killfeed-enter {
|
@keyframes current-match-killfeed-enter {
|
||||||
from {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -977,6 +1038,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.current-match-killfeed {
|
.current-match-killfeed {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -997,7 +1059,7 @@
|
|||||||
padding-inline: 3px;
|
padding-inline: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-match-killfeed__player {
|
.current-match-killfeed__player-name {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const CURRENT_MATCH_SCOREBOARDS = Object.freeze({
|
|||||||
"comunidad-hispana-01": "https://scoreboard.comunidadhll.es",
|
"comunidad-hispana-01": "https://scoreboard.comunidadhll.es",
|
||||||
"comunidad-hispana-02": "https://scoreboard.comunidadhll.es:5443",
|
"comunidad-hispana-02": "https://scoreboard.comunidadhll.es:5443",
|
||||||
});
|
});
|
||||||
const CURRENT_MATCH_KILL_FEED_LIMIT = 15;
|
const CURRENT_MATCH_KILL_FEED_LIMIT = 18;
|
||||||
const CURRENT_MATCH_WEAPONS = Object.freeze({
|
const CURRENT_MATCH_WEAPONS = Object.freeze({
|
||||||
"m1 garand": { label: "M1 Garand", icon: "m1_garand.PNG" },
|
"m1 garand": { label: "M1 Garand", icon: "m1_garand.PNG" },
|
||||||
mp40: { label: "MP40", icon: "mp40.PNG" },
|
mp40: { label: "MP40", icon: "mp40.PNG" },
|
||||||
@@ -225,11 +225,15 @@ function initializePlayerStats(nodes) {
|
|||||||
<p class="historical-state" id="current-match-player-stats-state" aria-live="polite">
|
<p class="historical-state" id="current-match-player-stats-state" aria-live="polite">
|
||||||
Cargando estadisticas en vivo...
|
Cargando estadisticas en vivo...
|
||||||
</p>
|
</p>
|
||||||
|
<p class="current-match-player-count" id="current-match-player-count">
|
||||||
|
Jugadores detectados: 0
|
||||||
|
</p>
|
||||||
<div class="historical-table-shell" id="current-match-player-stats-shell" hidden></div>
|
<div class="historical-table-shell" id="current-match-player-stats-shell" hidden></div>
|
||||||
`,
|
`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
nodes.playerStatsState = document.getElementById("current-match-player-stats-state");
|
nodes.playerStatsState = document.getElementById("current-match-player-stats-state");
|
||||||
|
nodes.playerCount = document.getElementById("current-match-player-count");
|
||||||
nodes.playerStatsShell = document.getElementById("current-match-player-stats-shell");
|
nodes.playerStatsShell = document.getElementById("current-match-player-stats-shell");
|
||||||
return {
|
return {
|
||||||
visibleSignature: "",
|
visibleSignature: "",
|
||||||
@@ -249,9 +253,9 @@ function renderKillFeed(data, nodes, state) {
|
|||||||
});
|
});
|
||||||
const events = [...state.byId.values()]
|
const events = [...state.byId.values()]
|
||||||
.sort(compareKillFeedEvents)
|
.sort(compareKillFeedEvents)
|
||||||
.slice(0, CURRENT_MATCH_KILL_FEED_LIMIT);
|
.slice(-CURRENT_MATCH_KILL_FEED_LIMIT);
|
||||||
state.byId = new Map(events.map((event) => [event.event_id, event]));
|
state.byId = new Map(events.map((event) => [event.event_id, event]));
|
||||||
state.latestEventId = events[0]?.event_id || state.latestEventId;
|
state.latestEventId = events[events.length - 1]?.event_id || state.latestEventId;
|
||||||
if (events.length === 0) {
|
if (events.length === 0) {
|
||||||
nodes.feedList.innerHTML = "";
|
nodes.feedList.innerHTML = "";
|
||||||
state.visibleSignature = "";
|
state.visibleSignature = "";
|
||||||
@@ -261,7 +265,7 @@ function renderKillFeed(data, nodes, state) {
|
|||||||
const visualEvents = events;
|
const visualEvents = events;
|
||||||
const visibleSignature = visualEvents.map((event) => event.event_id).join("|");
|
const visibleSignature = visualEvents.map((event) => event.event_id).join("|");
|
||||||
if (visibleSignature !== state.visibleSignature) {
|
if (visibleSignature !== state.visibleSignature) {
|
||||||
nodes.feedList.innerHTML = visualEvents.map(renderKillFeedRow).join("");
|
nodes.feedList.innerHTML = renderKillFeedColumns(visualEvents);
|
||||||
state.visibleSignature = visibleSignature;
|
state.visibleSignature = visibleSignature;
|
||||||
}
|
}
|
||||||
nodes.feedState.textContent = formatKillFeedCoverage(data.scope);
|
nodes.feedState.textContent = formatKillFeedCoverage(data.scope);
|
||||||
@@ -269,16 +273,34 @@ function renderKillFeed(data, nodes, state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function compareKillFeedEvents(left, right) {
|
function compareKillFeedEvents(left, right) {
|
||||||
const rightTime = Number(right.server_time);
|
|
||||||
const leftTime = Number(left.server_time);
|
const leftTime = Number(left.server_time);
|
||||||
if (Number.isFinite(rightTime) && Number.isFinite(leftTime) && rightTime !== leftTime) {
|
const rightTime = Number(right.server_time);
|
||||||
return rightTime - leftTime;
|
if (Number.isFinite(leftTime) && Number.isFinite(rightTime) && leftTime !== rightTime) {
|
||||||
|
return leftTime - rightTime;
|
||||||
}
|
}
|
||||||
return String(right.event_timestamp || "").localeCompare(String(left.event_timestamp || ""));
|
return (
|
||||||
|
String(left.event_timestamp || "").localeCompare(String(right.event_timestamp || "")) ||
|
||||||
|
String(left.event_id || "").localeCompare(String(right.event_id || ""))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderKillFeedColumns(events) {
|
||||||
|
const splitIndex = Math.ceil(events.length / 2);
|
||||||
|
return [events.slice(0, splitIndex), events.slice(splitIndex)]
|
||||||
|
.map(
|
||||||
|
(columnEvents) => `
|
||||||
|
<div class="current-match-killfeed__column">
|
||||||
|
${columnEvents.map(renderKillFeedRow).join("")}
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderKillFeedRow(event) {
|
function renderKillFeedRow(event) {
|
||||||
const weapon = resolveKillFeedWeapon(event.weapon);
|
const weapon = resolveKillFeedWeapon(event.weapon);
|
||||||
|
const killerTeam = getKillFeedTeamDisplay(event.killer_team);
|
||||||
|
const victimTeam = getKillFeedTeamDisplay(event.victim_team);
|
||||||
const teamkillBadge = event.is_teamkill
|
const teamkillBadge = event.is_teamkill
|
||||||
? '<span class="current-match-killfeed__teamkill">TK</span>'
|
? '<span class="current-match-killfeed__teamkill">TK</span>'
|
||||||
: "";
|
: "";
|
||||||
@@ -287,10 +309,15 @@ function renderKillFeedRow(event) {
|
|||||||
class="current-match-killfeed__row${event.is_teamkill ? " is-teamkill" : ""}"
|
class="current-match-killfeed__row${event.is_teamkill ? " is-teamkill" : ""}"
|
||||||
data-event-id="${escapeHtml(event.event_id || "")}"
|
data-event-id="${escapeHtml(event.event_id || "")}"
|
||||||
>
|
>
|
||||||
<strong class="current-match-killfeed__player current-match-killfeed__player--killer" title="${escapeHtml(event.killer_name || "Jugador no disponible")}">
|
<span class="current-match-killfeed__player current-match-killfeed__player--killer">
|
||||||
|
<strong class="current-match-killfeed__player-name" title="${escapeHtml(event.killer_name || "Jugador no disponible")}">
|
||||||
${escapeHtml(event.killer_name || "Jugador no disponible")}
|
${escapeHtml(event.killer_name || "Jugador no disponible")}
|
||||||
${teamkillBadge}
|
|
||||||
</strong>
|
</strong>
|
||||||
|
<span class="current-match-killfeed__player-meta">
|
||||||
|
${renderKillFeedTeamBadge(killerTeam)}
|
||||||
|
${teamkillBadge}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
<span
|
<span
|
||||||
class="current-match-killfeed__weapon"
|
class="current-match-killfeed__weapon"
|
||||||
title="${escapeHtml(weapon.label)}"
|
title="${escapeHtml(weapon.label)}"
|
||||||
@@ -300,12 +327,28 @@ function renderKillFeedRow(event) {
|
|||||||
<em>${escapeHtml(weapon.label)}</em>
|
<em>${escapeHtml(weapon.label)}</em>
|
||||||
</span>
|
</span>
|
||||||
<span class="current-match-killfeed__player current-match-killfeed__player--victim">
|
<span class="current-match-killfeed__player current-match-killfeed__player--victim">
|
||||||
|
<span class="current-match-killfeed__player-name" title="${escapeHtml(event.victim_name || "Objetivo no disponible")}">
|
||||||
${escapeHtml(event.victim_name || "Objetivo no disponible")}
|
${escapeHtml(event.victim_name || "Objetivo no disponible")}
|
||||||
</span>
|
</span>
|
||||||
|
${renderKillFeedTeamBadge(victimTeam)}
|
||||||
|
</span>
|
||||||
</article>
|
</article>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getKillFeedTeamDisplay(value) {
|
||||||
|
const team = getPlayerTeamDisplay(value);
|
||||||
|
return team.key === "unknown" ? { key: "unknown", label: "N/D" } : team;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderKillFeedTeamBadge(team) {
|
||||||
|
return `
|
||||||
|
<span class="current-match-killfeed__team-badge current-match-killfeed__team-badge--${team.key}">
|
||||||
|
${escapeHtml(team.label)}
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
function resolveKillFeedWeapon(value) {
|
function resolveKillFeedWeapon(value) {
|
||||||
const key = normalizeLookupText(value);
|
const key = normalizeLookupText(value);
|
||||||
return CURRENT_MATCH_WEAPONS[key] || {
|
return CURRENT_MATCH_WEAPONS[key] || {
|
||||||
@@ -335,6 +378,7 @@ function renderKillFeedWeaponIcon(weapon) {
|
|||||||
|
|
||||||
function renderPlayerStats(data, nodes, state) {
|
function renderPlayerStats(data, nodes, state) {
|
||||||
const items = Array.isArray(data.items) ? sortPlayerStats(data.items) : [];
|
const items = Array.isArray(data.items) ? sortPlayerStats(data.items) : [];
|
||||||
|
renderDetectedPlayerCount(items.length, nodes);
|
||||||
if (items.length === 0) {
|
if (items.length === 0) {
|
||||||
state.visibleSignature = "";
|
state.visibleSignature = "";
|
||||||
nodes.playerStatsShell.innerHTML = "";
|
nodes.playerStatsShell.innerHTML = "";
|
||||||
@@ -367,6 +411,12 @@ function renderPlayerStats(data, nodes, state) {
|
|||||||
setState(nodes.playerStatsState, "Estadisticas parciales derivadas de eventos recientes.");
|
setState(nodes.playerStatsState, "Estadisticas parciales derivadas de eventos recientes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderDetectedPlayerCount(count, nodes) {
|
||||||
|
if (nodes.playerCount) {
|
||||||
|
nodes.playerCount.textContent = `Jugadores detectados: ${count}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function sortPlayerStats(items) {
|
function sortPlayerStats(items) {
|
||||||
return [...items].sort(
|
return [...items].sort(
|
||||||
(left, right) =>
|
(left, right) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user