Pick hole cards from a grid instead of typing them
Typing "AH" into a two-character box is fine at a desk and miserable at a table: it needs a keyboard, it accepts nonsense like "ZZ", and it happily deals the same card to two players. The two card fields become face-up card slots. Tapping one opens a 52-card grid — four suit columns, thirteen rank rows, one tap per card — and picking the first card moves straight on to the second, because a dealer picking hole cards is always picking two. Cards already dealt elsewhere at the table are greyed out and say who has them, so a duplicate is visibly out of play rather than silently accepted. Cards are still stored as the same two plain characters everything has always read; the suit only becomes a symbol on its way to a human. That formatting is now shared, so the table pucks, the seat editor, the pot wizard, the hand history and the CSV all say A♥ K♦ rather than three of them saying AH KD. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
This commit is contained in:
@@ -481,24 +481,175 @@ body {
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.cardInput {
|
||||
/* The two hole-card slots: they look like cards face-up on the felt, and tapping
|
||||
one opens the picker rather than a keyboard. */
|
||||
.cardSlot {
|
||||
width: 100%;
|
||||
min-height: 52px;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
background: #fdfdfd;
|
||||
color: #111;
|
||||
border: 1px solid #3a3a3a;
|
||||
border-radius: 6px;
|
||||
padding: 0.35rem 0;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
font-family: var(--font-mono, monospace);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
cursor: pointer;
|
||||
transition: transform 0.12s ease, box-shadow 0.12s ease;
|
||||
}
|
||||
|
||||
.cardInput.cardRed {
|
||||
.cardSlot:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.cardSlot.cardRed {
|
||||
color: #c0392b;
|
||||
}
|
||||
|
||||
.cardSlot.cardSlotEmpty {
|
||||
background: #191919;
|
||||
color: #5c5c5c;
|
||||
border-style: dashed;
|
||||
border-color: #3f3f3f;
|
||||
box-shadow: none;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* ---------- Card picker ---------- */
|
||||
|
||||
#cardPickerOverlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.72);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
z-index: 95;
|
||||
}
|
||||
|
||||
#cardPickerOverlay[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#cardPickerSheet {
|
||||
width: 100%;
|
||||
max-width: 460px;
|
||||
max-height: 88vh;
|
||||
overflow-y: auto;
|
||||
background: linear-gradient(180deg, #242424, #1a1a1a);
|
||||
border: 1px solid #3a3a3a;
|
||||
border-bottom: none;
|
||||
border-radius: 16px 16px 0 0;
|
||||
padding: 0.35rem 0.9rem calc(1rem + env(safe-area-inset-bottom, 0px));
|
||||
box-shadow: 0 -14px 40px rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
|
||||
.cardPickerHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
.cardPickerHeader h2 {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
color: #f5f5f5;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.cardPickerHeader .holdemBtn {
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
#cardPickerSlots {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.7rem;
|
||||
}
|
||||
|
||||
.pickerSlot {
|
||||
flex: 1;
|
||||
min-height: 46px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #3a3a3a;
|
||||
background: #191919;
|
||||
color: #8a8a8a;
|
||||
font-family: var(--font-mono, monospace);
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* The slot the next tap will fill. */
|
||||
.pickerSlot.active {
|
||||
border-color: #d8b46a;
|
||||
background: #241d0f;
|
||||
color: #f0d9a8;
|
||||
}
|
||||
|
||||
.pickerSlot.cardRed {
|
||||
color: #e07b7b;
|
||||
}
|
||||
|
||||
#cardPickerGrid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.pickerCard {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.1rem;
|
||||
min-height: 44px;
|
||||
border-radius: 7px;
|
||||
border: 1px solid #d5d5d5;
|
||||
background: #fdfdfd;
|
||||
color: #111;
|
||||
font-family: var(--font-mono, monospace);
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: transform 0.1s ease;
|
||||
}
|
||||
|
||||
.pickerCard:hover:not(:disabled) {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.pickerCard.cardRed {
|
||||
color: #c0392b;
|
||||
}
|
||||
|
||||
.pickerCard.selected {
|
||||
outline: 3px solid #d8b46a;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
/* Already dealt somewhere else at the table — visibly out of play rather than
|
||||
silently accepting a duplicate. */
|
||||
.pickerCard:disabled {
|
||||
background: #1d1d1d;
|
||||
border-color: #303030;
|
||||
color: #4a4a4a;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.pickerSuit {
|
||||
font-size: 1.05em;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.seatContribution {
|
||||
border-top: 1px dashed #3a3a3a;
|
||||
padding-top: 0.4rem;
|
||||
@@ -1420,9 +1571,16 @@ body.hasActionBar #toastHost {
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
.seatEditorForm .cardInput {
|
||||
font-size: 1.35rem;
|
||||
min-height: 58px;
|
||||
.seatEditorForm .cardSlot {
|
||||
font-size: 1.5rem;
|
||||
min-height: 62px;
|
||||
}
|
||||
|
||||
/* Thirteen rows of cards need to stay reachable without the sheet running off
|
||||
the bottom of a phone. */
|
||||
.pickerCard {
|
||||
min-height: 46px;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.seatEditorForm .seatCardToggles {
|
||||
|
||||
Reference in New Issue
Block a user