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
52 lines
2.3 KiB
JavaScript
52 lines
2.3 KiB
JavaScript
// The legend and the key map must not drift apart.
|
|
//
|
|
// F, C and R are printed on the buttons they drive. A and U were on nothing at all,
|
|
// so a dealer who learned the first three from the action bar had no way to find out
|
|
// the other two existed. The guard against that happening again is this file.
|
|
const test = require("node:test");
|
|
const assert = require("node:assert");
|
|
const path = require("path");
|
|
|
|
const Shortcuts = require(path.join(
|
|
__dirname, "..", "..", "JoshHeaps.Net", "wwwroot", "js", "casino", "holdem", "shortcuts.js"));
|
|
|
|
test("every shortcut has a line in the legend", () => {
|
|
const documented = new Set(Shortcuts.LEGEND.map(entry => entry.action));
|
|
const missing = [...new Set(Object.values(Shortcuts.KEYS))].filter(action => !documented.has(action));
|
|
assert.deepEqual(missing, [], "a shortcut with no legend line is one nobody can find");
|
|
});
|
|
|
|
test("the legend doesn't describe shortcuts that don't exist", () => {
|
|
const real = new Set(Object.values(Shortcuts.KEYS));
|
|
const invented = Shortcuts.LEGEND.map(entry => entry.action).filter(action => !real.has(action));
|
|
assert.deepEqual(invented, []);
|
|
});
|
|
|
|
test("every legend line names its keys and says what they do", () => {
|
|
Shortcuts.LEGEND.forEach(entry => {
|
|
assert.ok(Array.isArray(entry.keys) && entry.keys.length > 0, `${entry.action} has no keys`);
|
|
assert.ok(entry.keys.every(key => typeof key === "string" && key.trim()), `${entry.action} has a blank key`);
|
|
assert.ok(entry.what && entry.what.trim().length > 3, `${entry.action} has no description`);
|
|
});
|
|
});
|
|
|
|
test("the keys named match the keys bound", () => {
|
|
// "Space" and "Enter" both drive advance; the map holds them as " " and "enter".
|
|
const spoken = { space: " ", enter: "enter", esc: "escape" };
|
|
Shortcuts.LEGEND.forEach(entry => {
|
|
entry.keys.forEach(label => {
|
|
const key = spoken[label.toLowerCase()] || label.toLowerCase();
|
|
assert.equal(Shortcuts.KEYS[key], entry.action,
|
|
`the legend says ${label} is ${entry.action}, the map disagrees`);
|
|
});
|
|
});
|
|
});
|
|
|
|
test("no two lines claim the same key", () => {
|
|
const seen = new Set();
|
|
Shortcuts.LEGEND.forEach(entry => entry.keys.forEach(key => {
|
|
assert.ok(!seen.has(key.toLowerCase()), `${key} is listed twice`);
|
|
seen.add(key.toLowerCase());
|
|
}));
|
|
});
|