Scoreboard: label warmup and round scores, count players and bots per team

The score caption says "Warmup, no rounds yet" during warmup and "Rounds
won, T vs CT" otherwise. Each team panel on the public page shows its
player and bot count, and its score as rounds won, or a Warmup label
during warmup. The top navigation scrolls sideways on narrow screens
instead of overflowing.
This commit is contained in:
Astra 2026-09-27 15:37:37 +01:00
parent 10694c69bc
commit b579941964
3 changed files with 14 additions and 6 deletions

View file

@ -51,7 +51,7 @@ function liveHeader(s) {
</div> </div>
<div class="live-stats"> <div class="live-stats">
<div><b>${s.count}<span class="faint">/${s.maxPlayers}</span></b><small>Players</small></div> <div><b>${s.count}<span class="faint">/${s.maxPlayers}</span></b><small>Players</small></div>
<div><b><span class="team t score">${s.scoreT}</span> <span class="faint">:</span> <span class="team ct score">${s.scoreCt}</span></b><small>T vs CT</small></div> <div><b><span class="team t score">${s.scoreT}</span> <span class="faint">:</span> <span class="team ct score">${s.scoreCt}</span></b><small>${s.warmup ? "Warmup, no rounds yet" : "Rounds won, T vs CT"}</small></div>
<div><b>${s.staffOnline}</b><small>Staff online</small></div> <div><b>${s.staffOnline}</b><small>Staff online</small></div>
</div> </div>
</div>`; </div>`;

View file

@ -28,8 +28,12 @@ async function server() {
} }
const side = (team, name, score) => { const side = (team, name, score) => {
const list = s.players.filter((p) => p.team === team).sort((a, b) => b.kills - a.kills); const list = s.players.filter((p) => p.team === team).sort((a, b) => b.kills - a.kills);
const humans = list.filter((p) => !p.bot).length;
return `<section class="panel side ${team === 3 ? "ct" : "t"}"> return `<section class="panel side ${team === 3 ? "ct" : "t"}">
<div class="panel-head"><h2>${name}</h2><b class="side-score">${score}</b></div> <div class="panel-head">
<div><h2>${name}</h2><p>${humans} ${humans === 1 ? "player" : "players"}${list.length > humans ? `, ${list.length - humans} ${list.length - humans === 1 ? "bot" : "bots"}` : ""}</p></div>
${s.warmup ? '<span class="side-warmup">Warmup</span>' : `<div class="side-score"><b>${score}</b><small>${score === 1 ? "round" : "rounds"} won</small></div>`}
</div>
${list.length ? `<table> ${list.length ? `<table>
<thead><tr><th>Player</th><th class="num">Kills</th><th class="num">Deaths</th><th class="num hide-sm">Ping</th></tr></thead> <thead><tr><th>Player</th><th class="num">Kills</th><th class="num">Deaths</th><th class="num hide-sm">Ping</th></tr></thead>
<tbody> <tbody>
@ -52,7 +56,7 @@ async function server() {
</div> </div>
<div class="live-stats"> <div class="live-stats">
<div><b>${s.count}<span class="faint">/${s.maxPlayers}</span></b><small>Players</small></div> <div><b>${s.count}<span class="faint">/${s.maxPlayers}</span></b><small>Players</small></div>
<div><b><span class="team t score">${s.scoreT}</span> <span class="faint">:</span> <span class="team ct score">${s.scoreCt}</span></b><small>T vs CT</small></div> <div><b><span class="team t score">${s.scoreT}</span> <span class="faint">:</span> <span class="team ct score">${s.scoreCt}</span></b><small>${s.warmup ? "Warmup, no rounds yet" : "Rounds won, T vs CT"}</small></div>
<div><b>${s.staffOnline}</b><small>Staff online</small></div> <div><b>${s.staffOnline}</b><small>Staff online</small></div>
</div> </div>
${s.address ? `<div class="live-join"> ${s.address ? `<div class="live-join">

View file

@ -950,9 +950,12 @@ dialog::backdrop { background: rgba(5, 6, 9, 0.65); }
.side { overflow: hidden; } .side { overflow: hidden; }
.side.ct { box-shadow: inset 0 3px 0 #6fa3e8; } .side.ct { box-shadow: inset 0 3px 0 #6fa3e8; }
.side.t { box-shadow: inset 0 3px 0 #e3b353; } .side.t { box-shadow: inset 0 3px 0 #e3b353; }
.side-score { font: 700 32px/1 var(--display); } .side-score { display: grid; justify-items: end; gap: 2px; }
.side.ct .side-score { color: #6fa3e8; } .side-score b { font: 700 32px/1 var(--display); }
.side.t .side-score { color: #e3b353; } .side-score small { color: var(--muted); font-size: 13px; }
.side.ct .side-score b { color: #6fa3e8; }
.side.t .side-score b { color: #e3b353; }
.side-warmup { color: var(--muted); font: 600 17px/1 var(--display); letter-spacing: 0.01em; }
.side .who .rank { display: flex; margin-top: 2px; font-size: 13px; } .side .who .rank { display: flex; margin-top: 2px; font-size: 13px; }
@media (max-width: 900px) { @media (max-width: 900px) {
@ -966,6 +969,7 @@ dialog::backdrop { background: rgba(5, 6, 9, 0.65); }
.topbar-inner { gap: 8px; padding: 0 12px; } .topbar-inner { gap: 8px; padding: 0 12px; }
.tabs { gap: 0; } .tabs { gap: 0; }
.tabs a { padding: 0 6px; font-size: 15px; } .tabs a { padding: 0 6px; font-size: 15px; }
.topbar nav { min-width: 0; overflow-x: auto; scrollbar-width: none; }
.signin { padding: 0 8px; } .signin { padding: 0 8px; }
.hide-xs { display: none; } .hide-xs { display: none; }
.show-xs { display: inline; } .show-xs { display: inline; }