Print the two shortcuts a dealer had no way to find
Seven keys drive this tool. Five of them are printed on the control they press -- F on Fold, C on Call, R on Raise, the return arrow on Deal and on Raise to, esc on Cancel. Two were printed on nothing at all: A opens the amount pad on All-in U takes back the last action A dealer who learned F, C and R from the buttons had no way to discover the other two existed. They are the two worth knowing: A is the fastest action in the tool and U is the one that saves a misclick. Both are on their controls now. The key lookup matches any of a button's classes, so the raise pad's four quick amounts can share one class for their looks while only All-in carries a key. And a legend in the sidebar, listing all seven with what they do, built from the same list the handlers are keyed off. There is a test that every key in the map has a line in the legend and that every line names a key that really is bound -- a shortcut with no line is one nobody can find, which is the whole bug this fixes. The panel is hidden on a touch device. A phone has no keys to press, and it is the same pointer question the touch-target rules ask rather than a guess about width. One thing I broke and fixed on the way. .actionKey pins itself to the top-right corner of a big action button. The undo control is a 30px pill with overflow hidden and no positioning context, so the U escaped it and floated above the action bar -- visible in the screenshot before I looked properly. It has its own inline class now, checked at six sizes: the cap sits inside the pill and inside the bar, and the pill is not clipped. 5 tests (249 total). Driven at six sizes across touch and pointer contexts: the undo pill shows U, the raise pad shows A on All-in and nothing on Min, half pot and Pot, the legend lists all seven, and it is display:none on a phone. Contrast clean, layout audit clean but for the landscape phone already known from #63, no console errors. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
This commit is contained in:
@@ -176,6 +176,17 @@ const ActionBar = {
|
||||
undo.className = "actionUndo";
|
||||
undo.title = `Undo ${undoLabel}`;
|
||||
undo.textContent = `↶ ${undoLabel}`;
|
||||
// U undoes, and nothing said so — this control was the only place a dealer
|
||||
// could have learned it, and it was the one action bar control without its
|
||||
// key printed on it.
|
||||
const key = document.createElement("kbd");
|
||||
// Its own class, not .actionKey: that one pins itself to the top-right
|
||||
// corner of a big action button, and this control is a 30px pill with
|
||||
// overflow hidden and no positioning context — the cap escaped it and
|
||||
// floated above the bar. Here the key belongs inline, after the label.
|
||||
key.className = "actionUndoKey";
|
||||
key.textContent = this.KEY_HINTS.actionUndo;
|
||||
undo.appendChild(key);
|
||||
undo.addEventListener("click", () => this.hooks.undoLast());
|
||||
row.appendChild(undo);
|
||||
}
|
||||
@@ -281,6 +292,8 @@ const ActionBar = {
|
||||
actionAdvance: "↵",
|
||||
raiseConfirm: "↵",
|
||||
raiseCancel: "esc",
|
||||
raiseAllIn: "A",
|
||||
actionUndo: "U",
|
||||
},
|
||||
|
||||
button(label, className, onClick, sublabel) {
|
||||
@@ -293,7 +306,10 @@ const ActionBar = {
|
||||
main.textContent = label;
|
||||
btn.appendChild(main);
|
||||
|
||||
const hint = this.KEY_HINTS[className];
|
||||
// Looked up by any of the button's classes, so a button can carry a shared
|
||||
// class for its looks and a specific one for its key — the raise pad's four
|
||||
// quick amounts are all raiseQuickBtn, but only All-in has a key.
|
||||
const hint = className.split(/\s+/).map(name => this.KEY_HINTS[name]).find(Boolean);
|
||||
if (hint) {
|
||||
const kbd = document.createElement("kbd");
|
||||
kbd.className = "actionKey";
|
||||
@@ -397,7 +413,7 @@ const ActionBar = {
|
||||
];
|
||||
options.forEach(option => {
|
||||
const value = Math.max(minTo, Math.min(option.value, maxTo));
|
||||
const btn = this.button(option.label, "raiseQuickBtn", () => {
|
||||
const btn = this.button(option.label, `raiseQuickBtn${option.label === "All-in" ? " raiseAllIn" : ""}`, () => {
|
||||
this.raiseDraft = value;
|
||||
this.render();
|
||||
}, Money.format(value));
|
||||
|
||||
@@ -458,6 +458,25 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
// Escape is Modal's job now, for this sheet and the five others that never had it.
|
||||
const rulingsOverlay = document.getElementById("rulingsOverlay");
|
||||
const closeRulings = () => { rulingsOverlay.hidden = true; };
|
||||
// The shortcut legend, built from the same list the handlers are keyed off, so a
|
||||
// shortcut can't exist without a line here saying what it does.
|
||||
const legend = document.getElementById("shortcutLegend");
|
||||
if (legend) {
|
||||
Shortcuts.LEGEND.forEach(entry => {
|
||||
const term = document.createElement("dt");
|
||||
entry.keys.forEach(key => {
|
||||
const kbd = document.createElement("kbd");
|
||||
kbd.className = "shortcutKey";
|
||||
kbd.textContent = key;
|
||||
term.appendChild(kbd);
|
||||
});
|
||||
const detail = document.createElement("dd");
|
||||
detail.textContent = entry.what;
|
||||
legend.appendChild(term);
|
||||
legend.appendChild(detail);
|
||||
});
|
||||
}
|
||||
|
||||
// An index across the top of the rulings sheet, one chip per ruling.
|
||||
//
|
||||
// This is opened mid-argument with players waiting, and it was nine rulings of
|
||||
|
||||
@@ -18,6 +18,23 @@ const Shortcuts = {
|
||||
escape: "cancel",
|
||||
},
|
||||
|
||||
// What each one does, in a dealer's words, for the legend in the sidebar.
|
||||
//
|
||||
// Lives beside KEYS because the two must not drift: F, C and R are printed on the
|
||||
// buttons they drive, but A and U were on nothing at all — a dealer who learned
|
||||
// the first three from the bar had no way to find out the other two existed. A
|
||||
// shortcut with no line here is a shortcut nobody can find, and there's a test
|
||||
// that says so.
|
||||
LEGEND: [
|
||||
{ keys: ["F"], action: "fold", what: "Fold" },
|
||||
{ keys: ["C"], action: "checkOrCall", what: "Check, or call the bet" },
|
||||
{ keys: ["R"], action: "raise", what: "Open the amount pad to bet or raise" },
|
||||
{ keys: ["A"], action: "allIn", what: "Put this player all-in" },
|
||||
{ keys: ["U"], action: "undo", what: "Take back the last action" },
|
||||
{ keys: ["Space", "Enter"], action: "advance", what: "Deal, or move to the next street" },
|
||||
{ keys: ["Esc"], action: "cancel", what: "Close the amount pad without betting" },
|
||||
],
|
||||
|
||||
mount(handlers) {
|
||||
this.handlers = handlers;
|
||||
document.addEventListener("keydown", e => this.onKey(e));
|
||||
|
||||
Reference in New Issue
Block a user