Let Quick Split handle the pot it used to send people away for
Quick Split answered the easy half of the question and printed a footnote for the hard half: if somebody was all-in for less, go set up the full table. That's the moment a dealer least wants to be setting up a table. A second mode takes what each player put in and lists the main pot and each side pot with who can win it, plus anything uncalled that goes back. Rows can be marked folded, so dead money lands in the right pot without its owner being able to win it. The running total is shown so the breakdown can be checked against the chips actually on the table. It reuses the same pot maths as the full table rather than growing a second implementation, which means the two screens can't drift apart and Quick Split inherits the uncalled-bet and everyone-folded handling that was fixed there. Also fixes hiding: these sections carry a `display` declaration, which outranks the browser's own [hidden] rule, so toggling `hidden` on them did nothing and both modes' controls showed at once. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
This commit is contained in:
@@ -11,6 +11,11 @@
|
||||
<p class="splitSubtitle">Chop a pot without setting up a table.</p>
|
||||
</header>
|
||||
|
||||
<div id="modeToggle" class="chipRow" role="group" aria-label="How the money went in">
|
||||
<button type="button" id="modeEvenBtn" class="choiceChip selected">Everyone matched</button>
|
||||
<button type="button" id="modeUnevenBtn" class="choiceChip">Someone's all-in</button>
|
||||
</div>
|
||||
|
||||
<div id="splitResult" aria-live="polite">
|
||||
<div id="splitResultLabel">Each player gets</div>
|
||||
<div id="splitResultAmount">$0.00</div>
|
||||
@@ -18,7 +23,18 @@
|
||||
<div id="splitDustNote" hidden></div>
|
||||
</div>
|
||||
|
||||
<section class="splitField">
|
||||
<div id="unevenResult" hidden aria-live="polite">
|
||||
<div id="unevenPots"></div>
|
||||
<p id="unevenEmpty" class="unevenEmpty">Enter what each player put in.</p>
|
||||
</div>
|
||||
|
||||
<section class="splitField unevenOnly" hidden>
|
||||
<span class="splitLabel">What each player put in</span>
|
||||
<div id="unevenRows"></div>
|
||||
<button type="button" id="addPlayerBtn" class="splitBtn splitBtnGhost">+ Add player</button>
|
||||
</section>
|
||||
|
||||
<section class="splitField evenOnly">
|
||||
<label for="potInput" class="splitLabel">Pot</label>
|
||||
<div class="potInputWrap">
|
||||
<span class="potCurrency">$</span>
|
||||
@@ -28,12 +44,12 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="splitField">
|
||||
<section class="splitField evenOnly">
|
||||
<span class="splitLabel" id="waysLabel">Split between</span>
|
||||
<div id="waysChoices" class="chipRow" role="group" aria-labelledby="waysLabel"></div>
|
||||
</section>
|
||||
|
||||
<section class="splitField">
|
||||
<section class="splitField evenOnly">
|
||||
<span class="splitLabel" id="chipLabel">Smallest chip in play</span>
|
||||
<div id="chipChoices" class="chipRow" role="group" aria-labelledby="chipLabel"></div>
|
||||
</section>
|
||||
@@ -43,12 +59,30 @@
|
||||
<a href="/casino/texasholdem" class="splitBtn splitBtnGhost">Full dealer table →</a>
|
||||
</div>
|
||||
|
||||
<p class="splitFootnote">
|
||||
Uneven pots — someone all-in for less — need the side-pot walkthrough on the
|
||||
<a href="/casino/texasholdem">full table</a>.
|
||||
<p class="splitFootnote evenOnly">
|
||||
If somebody was all-in for less than the others, switch to
|
||||
<strong>Someone's all-in</strong> above.
|
||||
</p>
|
||||
|
||||
<p class="splitFootnote unevenOnly" hidden>
|
||||
Pots are listed with who can win each. Award them by hand strength, best hand
|
||||
first. Nothing here is saved — the <a href="/casino/texasholdem">full table</a>
|
||||
keeps a log.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<template id="unevenRowTemplate">
|
||||
<div class="unevenRow">
|
||||
<span class="unevenRowLabel"></span>
|
||||
<div class="unevenAmountWrap">
|
||||
<span class="unevenCurrency">$</span>
|
||||
<input type="text" class="unevenAmount" inputmode="decimal" autocomplete="off" placeholder="0" />
|
||||
</div>
|
||||
<button type="button" class="unevenFoldBtn" aria-pressed="false">Folded</button>
|
||||
<button type="button" class="unevenRemoveBtn" aria-label="Remove player">✕</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@section Styles {
|
||||
<link href="/css/casino/quicksplit.css?v=@ViewData["cssVersion"]" rel="stylesheet" type="text/css" />
|
||||
}
|
||||
@@ -56,5 +90,6 @@
|
||||
@section Scripts {
|
||||
<script src="~/js/casino/holdem/money.js?v=@ViewData["cssVersion"]"></script>
|
||||
<script src="~/js/casino/holdem/splitCalculator.js?v=@ViewData["cssVersion"]"></script>
|
||||
<script src="~/js/casino/holdem/potCalculator.js?v=@ViewData["cssVersion"]"></script>
|
||||
<script src="~/js/casino/holdem/quickSplit.js?v=@ViewData["cssVersion"]"></script>
|
||||
}
|
||||
|
||||
@@ -45,6 +45,171 @@ body {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
/* ---------- Mode toggle ---------- */
|
||||
|
||||
#modeToggle {
|
||||
margin-bottom: 1.1rem;
|
||||
}
|
||||
|
||||
/* ---------- Uneven amounts ---------- */
|
||||
|
||||
#unevenRows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.45rem;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
.unevenRow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.unevenRowLabel {
|
||||
flex: none;
|
||||
width: 2rem;
|
||||
color: #8f8f8f;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.unevenAmountWrap {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
background: #141414;
|
||||
border: 1px solid #3a3a3a;
|
||||
border-radius: 10px;
|
||||
padding: 0 0.6rem;
|
||||
}
|
||||
|
||||
.unevenAmountWrap:focus-within {
|
||||
border-color: #d8b46a;
|
||||
}
|
||||
|
||||
.unevenCurrency {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.unevenAmount {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
color: #f2f2f2;
|
||||
font-family: inherit;
|
||||
font-size: 16px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
padding: 0.6rem 0;
|
||||
}
|
||||
|
||||
.unevenFoldBtn {
|
||||
flex: none;
|
||||
min-height: 44px;
|
||||
padding: 0 0.6rem;
|
||||
border-radius: 9px;
|
||||
border: 1px solid #3a3a3a;
|
||||
background: #232323;
|
||||
color: #8f8f8f;
|
||||
font-family: inherit;
|
||||
font-size: 0.72rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.unevenFoldBtn.selected {
|
||||
background: linear-gradient(180deg, #3d1f1f, #2c1515);
|
||||
border-color: #5b2626;
|
||||
color: #ffd6d6;
|
||||
}
|
||||
|
||||
.unevenRemoveBtn {
|
||||
flex: none;
|
||||
width: 30px;
|
||||
height: 44px;
|
||||
border: none;
|
||||
background: none;
|
||||
color: #6a6a6a;
|
||||
font-size: 0.85rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.unevenRemoveBtn:disabled {
|
||||
opacity: 0.3;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
#unevenResult {
|
||||
background: linear-gradient(160deg, #1f2a21, #161c17);
|
||||
border: 1px solid #2c3a2f;
|
||||
border-radius: 14px;
|
||||
padding: 0.9rem 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
#unevenResult[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.unevenPot {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.6rem;
|
||||
padding: 0.3rem 0;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.unevenPot + .unevenPot {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
.unevenPotLabel {
|
||||
flex: none;
|
||||
color: #d8b46a;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.unevenPotAmount {
|
||||
flex: none;
|
||||
color: #f2f2f2;
|
||||
font-weight: 600;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.unevenPotWho {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
text-align: right;
|
||||
color: #9a9a9a;
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.unevenPotReturn .unevenPotLabel,
|
||||
.unevenPotReturn .unevenPotAmount {
|
||||
color: #9a9a9a;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.unevenPotTotal {
|
||||
margin-top: 0.15rem;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.14) !important;
|
||||
}
|
||||
|
||||
.unevenPotTotal .unevenPotLabel {
|
||||
color: #8f9d92;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.unevenEmpty {
|
||||
margin: 0;
|
||||
color: #8f9d92;
|
||||
font-size: 0.82rem;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
/* ---------- The answer ---------- */
|
||||
|
||||
#splitResult {
|
||||
@@ -104,6 +269,12 @@ body {
|
||||
margin-bottom: 1.35rem;
|
||||
}
|
||||
|
||||
/* A `display` declaration outranks the browser's own [hidden] rule, so anything
|
||||
given one has to opt back out explicitly or toggling `hidden` does nothing. */
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.splitLabel {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
@@ -15,12 +15,28 @@ const QuickSplit = {
|
||||
ways: 2,
|
||||
chip: 1,
|
||||
|
||||
// "even" is the common case — one pot, everyone matched. "uneven" is the one this
|
||||
// screen used to send people back to the full table for: somebody all-in for less,
|
||||
// so the money splits into a main pot and side pots.
|
||||
mode: "even",
|
||||
entries: [],
|
||||
|
||||
mount() {
|
||||
this.potInput = document.getElementById("potInput");
|
||||
this.clearPotBtn = document.getElementById("clearPotBtn");
|
||||
this.entries = [{ amount: "", folded: false }, { amount: "", folded: false }, { amount: "", folded: false }];
|
||||
|
||||
this.renderWayChoices();
|
||||
this.renderChipChoices();
|
||||
this.renderUnevenRows();
|
||||
|
||||
document.getElementById("modeEvenBtn").addEventListener("click", () => this.setMode("even"));
|
||||
document.getElementById("modeUnevenBtn").addEventListener("click", () => this.setMode("uneven"));
|
||||
document.getElementById("addPlayerBtn").addEventListener("click", () => {
|
||||
this.entries.push({ amount: "", folded: false });
|
||||
this.renderUnevenRows();
|
||||
this.update();
|
||||
});
|
||||
|
||||
this.potInput.addEventListener("input", () => {
|
||||
this.sanitizePotInput();
|
||||
@@ -127,7 +143,112 @@ const QuickSplit = {
|
||||
});
|
||||
},
|
||||
|
||||
setMode(mode) {
|
||||
this.mode = mode;
|
||||
document.getElementById("modeEvenBtn").classList.toggle("selected", mode === "even");
|
||||
document.getElementById("modeUnevenBtn").classList.toggle("selected", mode === "uneven");
|
||||
|
||||
document.querySelectorAll(".evenOnly").forEach(el => { el.hidden = mode !== "even"; });
|
||||
document.querySelectorAll(".unevenOnly").forEach(el => { el.hidden = mode !== "uneven"; });
|
||||
document.getElementById("splitResult").hidden = mode !== "even";
|
||||
document.getElementById("unevenResult").hidden = mode !== "uneven";
|
||||
|
||||
this.update();
|
||||
},
|
||||
|
||||
renderUnevenRows() {
|
||||
const host = document.getElementById("unevenRows");
|
||||
const template = document.getElementById("unevenRowTemplate");
|
||||
host.innerHTML = "";
|
||||
|
||||
this.entries.forEach((entry, index) => {
|
||||
const row = template.content.firstElementChild.cloneNode(true);
|
||||
row.querySelector(".unevenRowLabel").textContent = `P${index + 1}`;
|
||||
|
||||
const amount = row.querySelector(".unevenAmount");
|
||||
amount.value = entry.amount;
|
||||
amount.setAttribute("aria-label", `Player ${index + 1} amount`);
|
||||
amount.addEventListener("input", () => {
|
||||
entry.amount = amount.value.replace(/[^0-9.]/g, "").replace(/(\..*)\./g, "$1");
|
||||
if (entry.amount !== amount.value) amount.value = entry.amount;
|
||||
this.update();
|
||||
});
|
||||
|
||||
// Folded money stays in the pot as dead money, but its owner can't win any
|
||||
// of it — which is exactly the distinction that makes side pots tricky.
|
||||
const fold = row.querySelector(".unevenFoldBtn");
|
||||
fold.classList.toggle("selected", entry.folded);
|
||||
fold.setAttribute("aria-pressed", String(entry.folded));
|
||||
fold.addEventListener("click", () => {
|
||||
entry.folded = !entry.folded;
|
||||
this.renderUnevenRows();
|
||||
this.update();
|
||||
});
|
||||
|
||||
const remove = row.querySelector(".unevenRemoveBtn");
|
||||
remove.disabled = this.entries.length <= 2;
|
||||
remove.addEventListener("click", () => {
|
||||
this.entries.splice(index, 1);
|
||||
this.renderUnevenRows();
|
||||
this.update();
|
||||
});
|
||||
|
||||
host.appendChild(row);
|
||||
});
|
||||
},
|
||||
|
||||
updateUneven() {
|
||||
const players = this.entries
|
||||
.map((entry, index) => ({ id: `P${index + 1}`, contribution: Number(entry.amount) || 0, folded: entry.folded }))
|
||||
.filter(p => p.contribution > 0);
|
||||
|
||||
const pots = PotCalculator.layers(players);
|
||||
const returns = PotCalculator.uncalledReturns(players);
|
||||
|
||||
const host = document.getElementById("unevenPots");
|
||||
const empty = document.getElementById("unevenEmpty");
|
||||
host.innerHTML = "";
|
||||
|
||||
if (pots.length === 0 && returns.length === 0) {
|
||||
empty.hidden = false;
|
||||
empty.textContent = players.length === 0
|
||||
? "Enter what each player put in."
|
||||
: "Nobody left who can win — un-fold whoever should take it.";
|
||||
return;
|
||||
}
|
||||
empty.hidden = true;
|
||||
|
||||
const addRow = (label, amount, who, className) => {
|
||||
const row = document.createElement("div");
|
||||
row.className = `unevenPot ${className || ""}`;
|
||||
const name = document.createElement("span");
|
||||
name.className = "unevenPotLabel";
|
||||
name.textContent = label;
|
||||
const value = document.createElement("span");
|
||||
value.className = "unevenPotAmount";
|
||||
value.textContent = Money.format(amount);
|
||||
const eligible = document.createElement("span");
|
||||
eligible.className = "unevenPotWho";
|
||||
eligible.textContent = who;
|
||||
row.appendChild(name);
|
||||
row.appendChild(value);
|
||||
row.appendChild(eligible);
|
||||
host.appendChild(row);
|
||||
};
|
||||
|
||||
pots.forEach(pot => addRow(pot.label, pot.amount, pot.eligible.join(", ")));
|
||||
returns.forEach(ret => addRow("Uncalled", ret.amount, `back to ${ret.id}`, "unevenPotReturn"));
|
||||
|
||||
const total = players.reduce((sum, p) => sum + p.contribution, 0);
|
||||
addRow("On the table", Math.round(total * 100) / 100, "", "unevenPotTotal");
|
||||
},
|
||||
|
||||
update() {
|
||||
if (this.mode === "uneven") {
|
||||
this.updateUneven();
|
||||
return;
|
||||
}
|
||||
|
||||
const potValue = Number(this.potInput.value);
|
||||
const pot = Number.isNaN(potValue) ? 0 : potValue;
|
||||
this.clearPotBtn.hidden = this.potInput.value === "";
|
||||
|
||||
Reference in New Issue
Block a user