Fix widow/play bugs, exit-anywhere; rework leaderboard + add game history

- Widow: preserve card selection across re-renders (no more deselecting)
- Play: reject a second card during trick resolution (fixes hand-count desync)
- Leave: exit available during bidding/widow/trump; a mid-game leave hands the
  seat to AI so the game continues; rooms with no humans are torn down
- Leaderboard: one-time flush + schema migration, win rate as the primary
  ranking metric, per-team shelem and per-seat bid tracking, avg score + bids won
- History: per-game round-by-round records persisted to history.json, a history
  screen, and a vertical round breakdown (with totals) shown to all players at
  hand/game end; result held for 15s

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
goyban
2026-07-05 12:29:16 +00:00
parent e0b9dde93e
commit 7c602b8e95
5 changed files with 452 additions and 41 deletions
+42 -5
View File
@@ -261,6 +261,7 @@
</div>
</div>
<p id="bid-waiting-msg" class="hint" style="min-height:20px"></p>
<button class="overlay-leave-btn" data-overlay-leave>🚪 Leave game</button>
</div>
</div>
@@ -276,6 +277,7 @@
</div>
<button id="btn-confirm-discard" class="btn-primary" disabled>Confirm Discard</button>
<p id="widow-waiting" class="hint" style="min-height:18px"></p>
<button class="overlay-leave-btn" data-overlay-leave>🚪 Leave game</button>
</div>
</div>
@@ -296,6 +298,7 @@
<div class="result-icon" style="font-size:2rem"></div>
<p id="trump-waiting-msg" class="hint"></p>
</div>
<button class="overlay-leave-btn" data-overlay-leave>🚪 Leave game</button>
</div>
</div>
@@ -306,6 +309,7 @@
<h3 id="hand-result-title"></h3>
<p id="hand-result-detail"></p>
<div id="hand-result-scores" class="result-scores"></div>
<div id="hand-round-breakdown" class="round-breakdown-wrap"></div>
<p class="hint">Next hand starting…</p>
</div>
</div>
@@ -316,6 +320,7 @@
<div class="result-icon big">🏆</div>
<h2 id="gameover-title"></h2>
<div id="gameover-scores" class="gameover-scores"></div>
<div id="gameover-breakdown" class="round-breakdown-wrap"></div>
<button id="btn-new-game" class="btn-primary">New Game</button>
</div>
</div>
@@ -367,21 +372,33 @@
<h2 id="profile-username" class="profile-name"></h2>
<div class="stat-grid">
<div class="stat-card">
<span class="stat-num" id="stat-games-played"></span>
<span class="stat-label">Games Played</span>
<span class="stat-num" id="stat-win-rate"></span>
<span class="stat-label">Win Rate</span>
</div>
<div class="stat-card">
<span class="stat-num" id="stat-games-won"></span>
<span class="stat-label">Games Won</span>
</div>
<div class="stat-card">
<span class="stat-num" id="stat-games-played"></span>
<span class="stat-label">Games Played</span>
</div>
<div class="stat-card">
<span class="stat-num" id="stat-shelem"></span>
<span class="stat-label">Shelems 🃏</span>
</div>
<div class="stat-card">
<span class="stat-num" id="stat-total-score"></span>
<span class="stat-label">Total Score</span>
<span class="stat-num" id="stat-bids-won"></span>
<span class="stat-label">Bids Won</span>
</div>
<div class="stat-card">
<span class="stat-num" id="stat-avg-score"></span>
<span class="stat-label">Avg Score</span>
</div>
</div>
<div class="profile-section">
<button id="btn-show-history" class="btn-secondary" style="width:100%">📜 Game History</button>
</div>
<div class="points-legend">
@@ -434,7 +451,7 @@
<table class="lb-table">
<thead>
<tr>
<th>#</th><th>Player</th><th>Avg Score</th><th>W</th><th>Played</th><th>🃏</th>
<th>#</th><th>Player</th><th>Win %</th><th>W</th><th>P</th><th>Avg</th><th title="Bids won">Bid</th><th title="Shelems">🃏</th>
</tr>
</thead>
<tbody id="lb-body"></tbody>
@@ -443,6 +460,26 @@
</div>
</div>
<!-- ══════════════ GAME HISTORY ══════════════ -->
<div id="screen-history" class="screen">
<div class="profile-wrap">
<div class="profile-box" style="max-width:560px">
<button id="btn-history-back" class="btn-back">← Back</button>
<div class="profile-avatar">📜</div>
<h2 id="history-title" class="profile-name">Game History</h2>
<!-- List of past games -->
<div id="history-list" class="history-list"><p class="hint">Loading…</p></div>
<!-- Detail of a selected game -->
<div id="history-detail" class="hidden">
<button id="btn-history-detail-back" class="btn-back" style="position:static;margin-bottom:8px">← All games</button>
<h3 id="history-detail-title"></h3>
<div id="history-detail-scores" class="gameover-scores"></div>
<div id="history-detail-breakdown" class="round-breakdown-wrap"></div>
</div>
</div>
</div>
</div>
<!-- ══════════════ EXIT CONFIRM ══════════════ -->
<div id="overlay-exit-confirm" class="overlay hidden">
<div class="overlay-box small" style="text-align:center">