feat(web): add undo button directly on the game board
Build and Deploy / build-and-push (push) Successful in 4m37s

Places a floating "↩ Undo" button at the bottom-right of the green felt
surface so it is visible without looking in the header. Both the board
button and the header button share the same handler; both track
undo_stack_len and disable when nothing can be undone.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-05-15 17:32:13 -07:00
parent 005e29d1ab
commit e17667d034
3 changed files with 20 additions and 7 deletions
+11
View File
@@ -98,6 +98,16 @@ button:disabled { opacity: 0.4; cursor: default; }
/* ── Board ───────────────────────────────────────────────────────────── */ /* ── Board ───────────────────────────────────────────────────────────── */
.board-undo {
position: absolute;
bottom: 24px;
right: 24px;
z-index: 50;
font-size: 15px;
padding: 8px 20px;
pointer-events: auto;
}
main { main {
flex: 1; flex: 1;
display: flex; display: flex;
@@ -108,6 +118,7 @@ main {
/* Full-bleed felt surface — flex:1 reliably fills main's remaining height. */ /* Full-bleed felt surface — flex:1 reliably fills main's remaining height. */
#board { #board {
position: relative;
flex: 1; flex: 1;
background: var(--felt); background: var(--felt);
display: flex; display: flex;
+1
View File
@@ -46,6 +46,7 @@
<main> <main>
<section id="board"> <section id="board">
<div id="card-area"></div> <div id="card-area"></div>
<button id="btn-board-undo" class="board-undo" title="Undo (Z)" disabled>↩ Undo</button>
</section> </section>
</main> </main>
+6 -5
View File
@@ -104,6 +104,7 @@ const hudTimer = document.getElementById("hud-timer");
const hudStock = document.getElementById("hud-stock"); const hudStock = document.getElementById("hud-stock");
const hudSeed = document.getElementById("hud-seed"); const hudSeed = document.getElementById("hud-seed");
const btnUndo = document.getElementById("btn-undo"); const btnUndo = document.getElementById("btn-undo");
const btnBoardUndo = document.getElementById("btn-board-undo");
const btnNew = document.getElementById("btn-new"); const btnNew = document.getElementById("btn-new");
const chkDraw3 = document.getElementById("chk-draw3"); const chkDraw3 = document.getElementById("chk-draw3");
const btnTheme = document.getElementById("btn-theme"); const btnTheme = document.getElementById("btn-theme");
@@ -244,6 +245,7 @@ function render(s) {
hudMoves.textContent = `Moves: ${s.move_count}`; hudMoves.textContent = `Moves: ${s.move_count}`;
if (hudStock) hudStock.textContent = `Stock: ${s.stock.length}`; if (hudStock) hudStock.textContent = `Stock: ${s.stock.length}`;
btnUndo.disabled = s.undo_stack_len === 0; btnUndo.disabled = s.undo_stack_len === 0;
btnBoardUndo.disabled = s.undo_stack_len === 0;
const visible = new Map(); const visible = new Map();
const addPile = (name, cards) => const addPile = (name, cards) =>
@@ -385,10 +387,9 @@ function flashIllegal(cardIds) {
// ── Input ───────────────────────────────────────────────────────────────────── // ── Input ─────────────────────────────────────────────────────────────────────
function attachHandlers() { function attachHandlers() {
btnUndo.addEventListener("click", () => { const doUndo = () => { const r = game.undo(); if (r.ok) render(r.snapshot); };
const r = game.undo(); btnUndo.addEventListener("click", doUndo);
if (r.ok) render(r.snapshot); btnBoardUndo.addEventListener("click", doUndo);
});
btnNew.addEventListener("click", () => startGame(randomSeed())); btnNew.addEventListener("click", () => startGame(randomSeed()));
btnWinNew.addEventListener("click", () => startGame(randomSeed())); btnWinNew.addEventListener("click", () => startGame(randomSeed()));
chkDraw3.addEventListener("change", () => { chkDraw3.addEventListener("change", () => {
@@ -404,7 +405,7 @@ function attachHandlers() {
document.addEventListener("keydown", (e) => { document.addEventListener("keydown", (e) => {
if (e.target.tagName === "INPUT") return; if (e.target.tagName === "INPUT") return;
if (e.key === "z" || e.key === "Z") { const r = game.undo(); if (r.ok) render(r.snapshot); } if (e.key === "z" || e.key === "Z") doUndo();
if (e.key === "n" || e.key === "N") startGame(randomSeed()); if (e.key === "n" || e.key === "N") startGame(randomSeed());
}); });