Make the dealer table usable on a phone
Two things were broken on a narrow screen. The seat ring is drawn on a radius measured from the table wrap, so at phone width the left- and right-most seats hung off the edge of the viewport — at a ten-handed table two players were simply not on screen. And tapping a seat opened an editor far enough down the page that it looked like nothing had happened. The ring is now inset by half a puck on phones, which keeps every seat on screen, and the pucks are narrower there so neighbours stop overlapping where the ring flattens out at the top and bottom. The seat editor becomes a bottom sheet that slides up over the table: grip, Done button, tap the same seat again to dismiss, table still visible above it. Its controls grow to thumb size, and every field goes to 16px — below that iOS zooms the page on focus and the dealer has to pinch back out mid-hand. Header actions become full-width tap targets, and the page padding tightens to give the table the width it needs. Nothing above 700px changes. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
This commit is contained in:
@@ -38,7 +38,11 @@
|
||||
|
||||
<aside id="holdemSidebar">
|
||||
<section id="seatEditorPanel" class="sidebarPanel seatEditorPanel">
|
||||
<h2 id="seatEditorTitle">Select a seat</h2>
|
||||
<div class="seatSheetGrip" aria-hidden="true"></div>
|
||||
<div class="seatEditorHeader">
|
||||
<h2 id="seatEditorTitle">Select a seat</h2>
|
||||
<button id="closeSeatEditorBtn" class="seatSheetClose" aria-label="Done editing this seat">Done</button>
|
||||
</div>
|
||||
<div id="seatEditorBody">
|
||||
<p class="fieldHint">Click a seat at the table to edit their name, cards, chips and anything else.</p>
|
||||
</div>
|
||||
|
||||
@@ -376,6 +376,27 @@ body {
|
||||
padding: 0.9rem;
|
||||
}
|
||||
|
||||
.seatEditorHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.seatEditorHeader h2 {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Grip and Done button are the sheet's furniture — no reason for either on a
|
||||
desktop sidebar, where the panel is just a panel. */
|
||||
.seatSheetGrip,
|
||||
.seatSheetClose {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.seatEditorPanel h2 {
|
||||
margin: 0 0 0.6rem;
|
||||
padding-bottom: 0.5rem;
|
||||
@@ -843,3 +864,193 @@ body {
|
||||
min-height: 44px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- Phones ----------
|
||||
Two things break on a narrow screen: seat pucks ring the table on a radius
|
||||
measured from the wrap, so the left- and right-most ones hang off the edge of
|
||||
the viewport; and the seat editor lives far enough down the page that tapping a
|
||||
seat looks like it did nothing. Inset the ring by half a puck, and float the
|
||||
editor up as a bottom sheet over the table. */
|
||||
@media (max-width: 700px) {
|
||||
#holdemApp {
|
||||
padding: 1rem 0.75rem 2rem;
|
||||
}
|
||||
|
||||
#holdemHeader {
|
||||
margin-bottom: 1rem;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
#holdemHeader h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.holdemSubtitle {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
#holdemHeaderActions {
|
||||
width: 100%;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
#holdemHeaderActions .holdemBtn {
|
||||
flex: 1 1 auto;
|
||||
justify-content: center;
|
||||
min-height: 46px;
|
||||
padding: 0.5rem 0.7rem;
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
/* Keeps every puck inside the viewport: the ring is drawn within this box,
|
||||
so half a puck of padding is exactly enough to stop the overhang. */
|
||||
#seatsLayer {
|
||||
inset: 26px 44px;
|
||||
}
|
||||
|
||||
/* Narrower than the desktop puck: at a full ten-handed table the ring is
|
||||
flattest at the top and bottom, and wide pucks are what made neighbours
|
||||
overlap there. The puck is only a summary — the real form is the sheet. */
|
||||
.seat {
|
||||
width: 64px;
|
||||
min-height: 42px;
|
||||
padding: 0.25rem 0.3rem;
|
||||
}
|
||||
|
||||
#tableWatermark {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
#potBadge {
|
||||
padding: 0.5rem 1.1rem;
|
||||
}
|
||||
|
||||
#potBadgeAmount {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.tableHint {
|
||||
margin-top: 0.75rem;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
/* ---- Seat editor as a bottom sheet ---- */
|
||||
|
||||
#seatEditorPanel {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 60;
|
||||
margin: 0;
|
||||
max-height: 74vh;
|
||||
overflow-y: auto;
|
||||
border-radius: 16px 16px 0 0;
|
||||
border-bottom: none;
|
||||
padding: 0.35rem 1rem 1.25rem;
|
||||
background: linear-gradient(180deg, #242424, #1a1a1a);
|
||||
box-shadow: 0 -14px 40px rgba(0, 0, 0, 0.65);
|
||||
transform: translateY(105%);
|
||||
transition: transform 0.25s ease;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
body.seatSheetOpen #seatEditorPanel {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.seatSheetGrip {
|
||||
display: block;
|
||||
width: 38px;
|
||||
height: 4px;
|
||||
margin: 0.35rem auto 0.5rem;
|
||||
border-radius: 999px;
|
||||
background: #4a4a4a;
|
||||
}
|
||||
|
||||
.seatSheetClose {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex: none;
|
||||
min-height: 44px;
|
||||
padding: 0.35rem 1.1rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #3a3a3a;
|
||||
background: linear-gradient(180deg, #2e2e2e, #232323);
|
||||
color: #ddd;
|
||||
font-size: 0.8rem;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* The sheet covers the bottom of the page while it's open — give the sidebar
|
||||
room so nothing is stranded underneath it. */
|
||||
body.seatSheetOpen #holdemSidebar {
|
||||
padding-bottom: 40vh;
|
||||
}
|
||||
|
||||
/* The seat form was sized for a 320px desktop sidebar. In the sheet it has a
|
||||
whole phone width to work with, so everything grows to thumb size — and
|
||||
every field goes to 16px, below which iOS zooms the page on focus and the
|
||||
dealer has to pinch back out mid-hand. */
|
||||
.seatEditorForm .seatNameInput,
|
||||
.seatEditorForm .amountOverrideInput,
|
||||
.seatEditorForm .chipCountInput,
|
||||
.seatEditorForm .customFieldLabel,
|
||||
.seatEditorForm .customFieldValue {
|
||||
font-size: 16px;
|
||||
min-height: 44px;
|
||||
padding: 0.4rem 0.6rem;
|
||||
}
|
||||
|
||||
.seatEditorForm .chipCountInput {
|
||||
width: 56px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.seatEditorForm .chipCounts {
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.seatEditorForm .chipSwatch {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.seatEditorForm .amountOverrideInput {
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
.seatEditorForm .cardInput {
|
||||
font-size: 1.35rem;
|
||||
min-height: 58px;
|
||||
}
|
||||
|
||||
.seatEditorForm .seatCardToggles {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.seatEditorForm .inHandToggle,
|
||||
.seatEditorForm .foldToggle {
|
||||
min-height: 44px;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.seatEditorForm .inHandToggle input,
|
||||
.seatEditorForm .foldToggle input {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.seatEditorForm .amountOverrideRow,
|
||||
.seatEditorForm .seatTotal {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.seatEditorForm .addFieldBtn {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
min-height: 44px;
|
||||
margin-top: 0.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById("closeSeatEditorBtn").addEventListener("click", () => Render.closeSeatEditor());
|
||||
|
||||
document.getElementById("closePotWizardBtn").addEventListener("click", () => PotWizard.close());
|
||||
document.getElementById("potWizardOverlay").addEventListener("click", e => {
|
||||
if (e.target.id === "potWizardOverlay") PotWizard.close();
|
||||
|
||||
@@ -106,7 +106,10 @@ const Render = {
|
||||
node.classList.toggle("seatSelected", index === this.selectedSeatIndex);
|
||||
|
||||
node.addEventListener("click", () => {
|
||||
this.selectedSeatIndex = index;
|
||||
// Tapping the open seat again closes it — on a phone the editor is a
|
||||
// sheet over the table, and the seat you just tapped is the closest
|
||||
// thing to hand for dismissing it.
|
||||
this.selectedSeatIndex = this.selectedSeatIndex === index ? null : index;
|
||||
this.renderSeats();
|
||||
this.renderSeatEditor();
|
||||
});
|
||||
@@ -175,10 +178,20 @@ const Render = {
|
||||
|
||||
// ---- Seat editor panel (the full form for whichever seat is selected) ----
|
||||
|
||||
closeSeatEditor() {
|
||||
this.selectedSeatIndex = null;
|
||||
this.renderSeats();
|
||||
this.renderSeatEditor();
|
||||
},
|
||||
|
||||
renderSeatEditor() {
|
||||
const title = document.getElementById("seatEditorTitle");
|
||||
const body = document.getElementById("seatEditorBody");
|
||||
|
||||
// Drives the mobile bottom sheet: the panel only slides up over the table
|
||||
// while a seat is actually being edited.
|
||||
document.body.classList.toggle("seatSheetOpen", this.selectedSeatIndex !== null);
|
||||
|
||||
if (this.selectedSeatIndex === null) {
|
||||
title.textContent = "Select a seat";
|
||||
body.innerHTML = '<p class="fieldHint">Click a seat at the table to edit their name, cards, chips and anything else.</p>';
|
||||
|
||||
Reference in New Issue
Block a user