Hold'em dealer: 55 polish rounds, one merge #101
@@ -163,7 +163,7 @@
|
|||||||
<template id="seatTemplate">
|
<template id="seatTemplate">
|
||||||
<div class="seat" draggable="true">
|
<div class="seat" draggable="true">
|
||||||
<div class="seatChairNumber"></div>
|
<div class="seatChairNumber"></div>
|
||||||
<button class="dealerChip" title="Make this seat the dealer button">D</button>
|
<button class="dealerChip" type="button" title="Make this seat the dealer button">D</button>
|
||||||
<span class="blindBadge sbBadge">SB</span>
|
<span class="blindBadge sbBadge">SB</span>
|
||||||
<span class="blindBadge bbBadge">BB</span>
|
<span class="blindBadge bbBadge">BB</span>
|
||||||
<div class="seatPuckName"></div>
|
<div class="seatPuckName"></div>
|
||||||
|
|||||||
@@ -591,7 +591,6 @@ button,
|
|||||||
font-size: 0.68rem;
|
font-size: 0.68rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
opacity: 0.32;
|
|
||||||
transition: opacity 0.15s ease;
|
transition: opacity 0.15s ease;
|
||||||
/* A dealer puck should look like a puck — small, sitting on the rim of its seat.
|
/* A dealer puck should look like a puck — small, sitting on the rim of its seat.
|
||||||
But tapping it hands the button to that seat and re-posts the blinds, and 22px
|
But tapping it hands the button to that seat and re-posts the blinds, and 22px
|
||||||
@@ -622,16 +621,40 @@ button,
|
|||||||
left: -18px;
|
left: -18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dealerChip:focus-visible {
|
/* A poker table has one dealer button. This one drew nine.
|
||||||
opacity: 1;
|
|
||||||
|
Every seat carried a puck — the button's, and eight ghosts at 0.32 opacity that
|
||||||
|
were there to be pressed. Measured on a nine-seat table: eight pale discs, all
|
||||||
|
eight showing the letter D, one of them real. Finding the button meant comparing
|
||||||
|
nine identical shapes for the one that's gold, when it should be the only thing
|
||||||
|
of its kind on the felt. The ghosts also sat on top of their neighbours: every
|
||||||
|
remaining "something important is covered" offender on a crowded table was a
|
||||||
|
seat covered by the seat-next-door's ghost puck.
|
||||||
|
|
||||||
|
So a seat that doesn't have the button doesn't draw one. The affordance is still
|
||||||
|
there — hovering a seat fades its slot in, which is a preview of where the button
|
||||||
|
would go — and on touch, where there is no hover, "Give the button" has always
|
||||||
|
been in the seat's long-press menu. Keyboard reaches it by focus.
|
||||||
|
|
||||||
|
pointer-events matters as much as the opacity: an invisible puck that still takes
|
||||||
|
taps would be worse than a visible one. */
|
||||||
|
.dealerChip:not(.active) {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
.seat:hover .dealerChip {
|
.seat:hover .dealerChip:not(.active) {
|
||||||
opacity: 1;
|
opacity: 0.5;
|
||||||
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dealerChip:not(.active):focus-visible {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.dealerChip.active {
|
.dealerChip.active {
|
||||||
background: radial-gradient(circle at 35% 30%, #ffe9a8, #f5d547 55%, #cba428 100%);
|
background: radial-gradient(circle at 35% 30%, #ffe9a8, #f5d547 55%, #cba428 100%);
|
||||||
border-color: #a9782f;
|
border-color: #a9782f;
|
||||||
|
|||||||
@@ -174,8 +174,18 @@ const Render = {
|
|||||||
node.querySelector(".seatChairNumber").textContent = index + 1;
|
node.querySelector(".seatChairNumber").textContent = index + 1;
|
||||||
|
|
||||||
const dealerChip = node.querySelector(".dealerChip");
|
const dealerChip = node.querySelector(".dealerChip");
|
||||||
dealerChip.classList.toggle("active", index === dealerIndex);
|
const hasButton = index === dealerIndex;
|
||||||
|
dealerChip.classList.toggle("active", hasButton);
|
||||||
dealerChip.classList.toggle("hidden", !!this.state.dedicatedDealer);
|
dealerChip.classList.toggle("hidden", !!this.state.dedicatedDealer);
|
||||||
|
// Every one of these announced itself as "D", so a screen reader heard a row
|
||||||
|
// of nine identical buttons and couldn't tell which seat held the real one.
|
||||||
|
// The label now says whose it is, or what pressing it would do.
|
||||||
|
const who = (player.name || "").trim() || `seat ${index + 1}`;
|
||||||
|
const chipLabel = hasButton
|
||||||
|
? `${who} has the dealer button`
|
||||||
|
: `Give the dealer button to ${who}`;
|
||||||
|
dealerChip.setAttribute("aria-label", chipLabel);
|
||||||
|
dealerChip.title = chipLabel;
|
||||||
// Tapping the puck is the same act as "Give the button" in the seat menu,
|
// Tapping the puck is the same act as "Give the button" in the seat menu,
|
||||||
// so it goes through the same hook — otherwise this one path would move
|
// so it goes through the same hook — otherwise this one path would move
|
||||||
// the button without moving the blinds that follow it.
|
// the button without moving the blinds that follow it.
|
||||||
|
|||||||
@@ -514,6 +514,34 @@ const LayoutAudit = {
|
|||||||
return { name: "a seat's centre belongs to that seat", offenders };
|
return { name: "a seat's centre belongs to that seat", offenders };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// A poker table has one dealer button. Nine pucks all showing "D", one of them
|
||||||
|
// gold, turns the most-read marker on the felt into a spot-the-difference — and
|
||||||
|
// a screen reader heard nine buttons named "D" with nothing to tell them apart.
|
||||||
|
// Both halves are checked here: what's drawn, and what it announces itself as.
|
||||||
|
oneDealerButton() {
|
||||||
|
const chips = [...document.querySelectorAll(".dealerChip")];
|
||||||
|
const shown = chips.filter(chip => {
|
||||||
|
const style = getComputedStyle(chip);
|
||||||
|
return style.display !== "none" && style.visibility !== "hidden" &&
|
||||||
|
parseFloat(style.opacity) > 0.05;
|
||||||
|
});
|
||||||
|
const offenders = [];
|
||||||
|
|
||||||
|
if (shown.length > 1) {
|
||||||
|
offenders.push(`${shown.length} dealer buttons drawn on the felt at once`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const labels = chips.map(chip => chip.getAttribute("aria-label") || chip.textContent.trim());
|
||||||
|
const duplicated = labels.filter((label, i) => labels.indexOf(label) !== i);
|
||||||
|
if (duplicated.length) {
|
||||||
|
offenders.push(
|
||||||
|
`${duplicated.length + 1} dealer buttons announce themselves as "${duplicated[0]}"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { name: "the felt shows one dealer button", offenders };
|
||||||
|
},
|
||||||
|
|
||||||
// ---- Runner ----
|
// ---- Runner ----
|
||||||
|
|
||||||
runAll(options = {}) {
|
runAll(options = {}) {
|
||||||
@@ -527,6 +555,7 @@ const LayoutAudit = {
|
|||||||
this.horizontalOverflow(),
|
this.horizontalOverflow(),
|
||||||
this.fieldFontSize(),
|
this.fieldFontSize(),
|
||||||
this.seatOwnership(),
|
this.seatOwnership(),
|
||||||
|
this.oneDealerButton(),
|
||||||
];
|
];
|
||||||
if (options.includeTouchTargets) checks.push(this.touchTargets(options.minimumTarget));
|
if (options.includeTouchTargets) checks.push(this.touchTargets(options.minimumTarget));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user