games: the casino moves out, and gets a clock of its own
The tables were living in the news app's shell: Pete's face in the header and the footer, the channel nav, search, the reader, the weather canvas, the PWA. A casino is not a news page with a felt on it. So it gets its own layout. What carries over is the design language — the four palette vars, Fredoka/Nunito, the fat rounded cards, the dropped shadow. What doesn't is every control it has no use for. gamesPage stops embedding the news pageData, which is what keeps the furniture from drifting back one convenient field at a time. It keeps a clock, but tells a different joke with it: Casinopolis by day, Casino Night Zone from six, palette and felt and the sign over the door all changing together. The rule lives in roomAt() for the first paint and again in the browser, so a player abroad gets their own evening. And the cards are cards now — corner indices in both corners, the bottom one upside down as printed, pips on the three-by-seven grid every real deck has used for four hundred years, courts as a letter with the suit over each shoulder. Driven in a real browser, both rooms, dealt through to a payout.
This commit is contained in:
@@ -73,18 +73,104 @@
|
||||
return wrap;
|
||||
}
|
||||
|
||||
// Pip layouts, the way a real deck lays them out — which is not "N suits in a
|
||||
// row". Each entry is [column, row] on a 3×7 grid: three columns, seven rows,
|
||||
// the same skeleton every printed deck has used for about four hundred years.
|
||||
// A pip below the halfway line is printed upside down, so it does that here.
|
||||
//
|
||||
// Sevens and tens have a pip that sits *between* two rows, so those span a pair
|
||||
// of rows and centre themselves across the pair.
|
||||
var PIPS = {
|
||||
"A": [[2, 4]],
|
||||
"2": [[2, 1], [2, 7]],
|
||||
"3": [[2, 1], [2, 4], [2, 7]],
|
||||
"4": [[1, 1], [3, 1], [1, 7], [3, 7]],
|
||||
"5": [[1, 1], [3, 1], [2, 4], [1, 7], [3, 7]],
|
||||
"6": [[1, 1], [3, 1], [1, 4], [3, 4], [1, 7], [3, 7]],
|
||||
"7": [[1, 1], [3, 1], [2, "2/4"], [1, 4], [3, 4], [1, 7], [3, 7]],
|
||||
"8": [[1, 1], [3, 1], [2, "2/4"], [1, 4], [3, 4], [2, "4/6"], [1, 7], [3, 7]],
|
||||
"9": [[1, 1], [3, 1], [1, 3], [3, 3], [2, 4], [1, 5], [3, 5], [1, 7], [3, 7]],
|
||||
"10": [[1, 1], [3, 1], [2, "2/4"], [1, 3], [3, 3], [1, 5], [3, 5], [2, "4/6"], [1, 7], [3, 7]],
|
||||
};
|
||||
|
||||
var COURT = { "J": "Jack", "Q": "Queen", "K": "King" };
|
||||
|
||||
function corner(face, where) {
|
||||
var el = document.createElement("span");
|
||||
el.className = "pete-card-corner pete-card-corner-" + where;
|
||||
var r = document.createElement("span");
|
||||
r.className = "pete-card-corner-rank";
|
||||
r.textContent = face.rank;
|
||||
var s = document.createElement("span");
|
||||
s.className = "pete-card-corner-suit";
|
||||
s.textContent = face.suit;
|
||||
el.appendChild(r);
|
||||
el.appendChild(s);
|
||||
return el;
|
||||
}
|
||||
|
||||
function pip(face, col, row) {
|
||||
var el = document.createElement("span");
|
||||
el.className = "pete-card-pip";
|
||||
el.textContent = face.suit;
|
||||
el.style.gridColumn = String(col);
|
||||
// A row given as "2/4" spans that pair and centres between them.
|
||||
el.style.gridRow = String(row);
|
||||
// The bottom half of a real card is printed the other way up.
|
||||
var mid = typeof row === "number" ? row > 4 : row === "4/6";
|
||||
if (mid) el.dataset.flip = "1";
|
||||
return el;
|
||||
}
|
||||
|
||||
// paintFace draws an actual playing card: index in two opposite corners, and
|
||||
// either the pips or a court figure in the middle. The dealer's cards and
|
||||
// yours use the same face, because they came out of the same shoe.
|
||||
function paintFace(front, face) {
|
||||
front.dataset.red = face.red ? "1" : "0";
|
||||
front.innerHTML = "";
|
||||
var rank = document.createElement("span");
|
||||
rank.className = "pete-card-rank";
|
||||
rank.textContent = face.rank;
|
||||
var suit = document.createElement("span");
|
||||
suit.className = "pete-card-suit";
|
||||
suit.textContent = face.suit;
|
||||
front.appendChild(rank);
|
||||
front.appendChild(suit);
|
||||
front.setAttribute("aria-label", face.label);
|
||||
|
||||
front.appendChild(corner(face, "tl"));
|
||||
|
||||
var body = document.createElement("span");
|
||||
if (COURT[face.rank]) {
|
||||
// Court cards: the letter, big, with the suit sitting over each shoulder.
|
||||
// No portrait — a drawn face would fight the room, and this reads instantly.
|
||||
body.className = "pete-card-court";
|
||||
var top = document.createElement("span");
|
||||
top.className = "pete-card-court-suit";
|
||||
top.textContent = face.suit;
|
||||
var letter = document.createElement("span");
|
||||
letter.className = "pete-card-court-letter";
|
||||
letter.textContent = face.rank;
|
||||
var bot = document.createElement("span");
|
||||
bot.className = "pete-card-court-suit";
|
||||
bot.dataset.flip = "1";
|
||||
bot.textContent = face.suit;
|
||||
body.appendChild(top);
|
||||
body.appendChild(letter);
|
||||
body.appendChild(bot);
|
||||
} else {
|
||||
body.className = "pete-card-pips";
|
||||
// An ace gets one big pip in the middle, the way an ace does.
|
||||
if (face.rank === "A") body.dataset.ace = "1";
|
||||
var spots = PIPS[face.rank] || [];
|
||||
for (var i = 0; i < spots.length; i++) {
|
||||
body.appendChild(pip(face, spots[i][0], spots[i][1]));
|
||||
}
|
||||
}
|
||||
front.appendChild(body);
|
||||
|
||||
front.appendChild(corner(face, "br"));
|
||||
|
||||
front.setAttribute("aria-label", ariaFor(face));
|
||||
}
|
||||
|
||||
// "A♠" is not something a screen reader should be asked to pronounce.
|
||||
function ariaFor(face) {
|
||||
var SUITS = { "♠": "spades", "♥": "hearts", "♦": "diamonds", "♣": "clubs" };
|
||||
var name = COURT[face.rank] || (face.rank === "A" ? "Ace" : face.rank);
|
||||
var suit = SUITS[face.suit];
|
||||
return suit ? name + " of " + suit : face.label;
|
||||
}
|
||||
|
||||
// turnOver flips a face-down card up, now that we've been told what it is.
|
||||
|
||||
Reference in New Issue
Block a user