Track the betting live so the dealer taps instead of types
Until now a dealer kept the money in their head and typed each player's total into a form. This adds the running hand: blinds post themselves, every seat has a stack, and one tap per decision moves the action on. The bar sits at the bottom of the screen where a thumb already is, and shows only what's true right now — Fold, then Check or Call with the amount owed, then Bet or Raise. Calling more than a player has left says "Call all-in" rather than quoting a number they can't cover. Raising offers min, half pot, pot and all-in before it offers a keypad, because a dealer calling "raise to sixty" wants a button. When everyone has answered, the bar becomes Deal Flop, then Turn, River, and finally Showdown, which hands off to the pot wizard that already existed. Winnings go straight back in front of the winner, so the next hand's stacks are already right. The money hooks into what was already there rather than running beside it: a street's chips sweep into each seat's amountOverride, the same field the pot badge, the pot wizard, the session standings and the CSV export all read. So nothing downstream changed, and a dealer who prefers the old typed workflow still has it. Tables saved before this exist without any of these fields, so load() fills them in rather than making someone reset a table mid-session. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
This commit is contained in:
@@ -594,6 +594,10 @@ body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.8rem;
|
||||
/* Grid items default to min-width:auto, so anything with a wide min-content —
|
||||
a side-by-side field row, say — would push this column past the viewport and
|
||||
drag the table out with it. */
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.sidebarPanel {
|
||||
@@ -790,16 +794,245 @@ body {
|
||||
|
||||
/* ---------- Pot wizard ---------- */
|
||||
|
||||
/* ---------- Action bar ---------- */
|
||||
|
||||
#actionBar {
|
||||
position: fixed;
|
||||
/* Centred with auto margins rather than 100vw + translate: on a phone with a
|
||||
scrollbar, 100vw is wider than the viewport and the overflow drags the whole
|
||||
table sideways. */
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: 0 auto;
|
||||
z-index: 55;
|
||||
max-width: 720px;
|
||||
background: linear-gradient(180deg, #232323, #191919);
|
||||
border: 1px solid #383838;
|
||||
border-bottom: none;
|
||||
border-radius: 14px 14px 0 0;
|
||||
padding: 0.6rem 0.75rem calc(0.75rem + env(safe-area-inset-bottom, 0px));
|
||||
box-shadow: 0 -12px 34px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
#actionBar[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* The bar is fixed over the page, so the sidebar needs room to scroll past it. */
|
||||
body.hasActionBar #holdemSidebar {
|
||||
padding-bottom: 9rem;
|
||||
}
|
||||
|
||||
.actionStatus {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.6rem;
|
||||
margin-bottom: 0.55rem;
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.actionStreet {
|
||||
color: #d8b46a;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.actionPot {
|
||||
color: #e9e9e9;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.actionWho {
|
||||
margin-left: auto;
|
||||
color: #9c9c9c;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.actionButtons {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.actionBtn {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.1rem;
|
||||
min-height: 56px;
|
||||
padding: 0.5rem 0.6rem;
|
||||
border-radius: 11px;
|
||||
border: 1px solid #3a3a3a;
|
||||
background: linear-gradient(180deg, #2e2e2e, #232323);
|
||||
color: #eee;
|
||||
font-family: inherit;
|
||||
font-size: 0.95rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.12s ease;
|
||||
}
|
||||
|
||||
.actionBtn:hover {
|
||||
border-color: #4a4a4a;
|
||||
background: linear-gradient(180deg, #383838, #2a2a2a);
|
||||
}
|
||||
|
||||
.actionBtn:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.actionBtnLabel {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.actionBtnSub {
|
||||
font-size: 0.72rem;
|
||||
color: #a8a8a8;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.actionFold {
|
||||
background: linear-gradient(180deg, #3d1f1f, #2c1515);
|
||||
border-color: #5b2626;
|
||||
color: #ffd6d6;
|
||||
}
|
||||
|
||||
.actionCheck,
|
||||
.actionCall {
|
||||
background: linear-gradient(180deg, #16783a, #0d5225);
|
||||
border-color: #1e8449;
|
||||
color: #ecffef;
|
||||
}
|
||||
|
||||
.actionCheck .actionBtnSub,
|
||||
.actionCall .actionBtnSub {
|
||||
color: #bfe8cb;
|
||||
}
|
||||
|
||||
.actionRaise {
|
||||
background: linear-gradient(180deg, #3a2f18, #241d0f);
|
||||
border-color: #a9782f;
|
||||
color: #f0d9a8;
|
||||
}
|
||||
|
||||
.actionAdvance {
|
||||
background: linear-gradient(180deg, #2b3f57, #1b2a3a);
|
||||
border-color: #3d5f83;
|
||||
color: #dceaf8;
|
||||
}
|
||||
|
||||
/* ---------- Raise pad ---------- */
|
||||
|
||||
.raiseQuick {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.raiseQuickBtn {
|
||||
min-height: 48px;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.raiseQuickBtn.selected {
|
||||
border-color: #d8b46a;
|
||||
background: linear-gradient(180deg, #3a2f18, #241d0f);
|
||||
color: #f0d9a8;
|
||||
}
|
||||
|
||||
.raiseEntry {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.raiseInput {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
background: #141414;
|
||||
border: 1px solid #3a3a3a;
|
||||
border-radius: 11px;
|
||||
color: #f2f2f2;
|
||||
font-family: inherit;
|
||||
font-size: 16px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
text-align: center;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.raiseInput:focus {
|
||||
outline: none;
|
||||
border-color: #d8b46a;
|
||||
}
|
||||
|
||||
.raiseCancel {
|
||||
flex: 0 0 auto;
|
||||
min-width: 84px;
|
||||
}
|
||||
|
||||
.raiseConfirm {
|
||||
flex: 0 0 auto;
|
||||
min-width: 116px;
|
||||
background: linear-gradient(180deg, #3a2f18, #241d0f);
|
||||
border-color: #a9782f;
|
||||
color: #f0d9a8;
|
||||
}
|
||||
|
||||
/* Whose turn it is, shown on the table itself as well as in the bar. */
|
||||
.seat.seatActing {
|
||||
border-color: #d8b46a;
|
||||
box-shadow:
|
||||
0 0 0 2px rgba(216, 180, 106, 0.45),
|
||||
0 4px 16px rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
.seatPuckStack {
|
||||
font-size: 0.58rem;
|
||||
color: #8f8f8f;
|
||||
font-variant-numeric: tabular-nums;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
.blindsRow {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.blindsRow .fieldRow {
|
||||
flex: 1 1 120px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.blindsRow input {
|
||||
min-width: 0;
|
||||
width: 5rem;
|
||||
}
|
||||
|
||||
/* ---------- Toasts ---------- */
|
||||
|
||||
#toastHost {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 1.25rem;
|
||||
transform: translateX(-50%);
|
||||
margin: 0 auto;
|
||||
z-index: 80;
|
||||
width: min(560px, calc(100vw - 1.5rem));
|
||||
max-width: 560px;
|
||||
padding: 0 0.75rem;
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
transition: bottom 0.18s ease;
|
||||
}
|
||||
|
||||
/* Sit above the action bar rather than on top of it, so an Undo never covers the
|
||||
Fold button the dealer is reaching for. */
|
||||
body.hasActionBar #toastHost {
|
||||
bottom: calc(9rem + env(safe-area-inset-bottom, 0px));
|
||||
}
|
||||
|
||||
.toast {
|
||||
|
||||
Reference in New Issue
Block a user