Something went wrong. Try again.
Web frontend and supporting services for lance.blue
Something went wrong. Try again.
5.3 kB · 149 lines
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150/** * The daily card's ground belongs to the right of its text, and the card has * to leave room for it there. * * `.daily-text` holds the readable column and the terrain tile side by side, * and the tile is a fixed 8rem. The readable column got whatever the card had * left - about 200px on the front page, narrower than the launch control, * which does not wrap - so the blurb and the battle values ran on under the * tile and were read through it. * * A media query was meant to catch that, but it asked about the window: the * window was 1440px wide while the column that had run out was 344px. The fix * is not to move the tile. It is for the card's own split to have a floor * under the side that holds both of them, and for the board - the one thing * here that scales - to give up the difference. * * The rule this file keeps: that floor is at least the readable column, the * gap and the tile added up. The arithmetic is here rather than a remembered * number, because it moves the moment anyone touches the tile's width, the * gap, or what the launch control needs. * * Run with `npm test`. */import { test } from "node:test";import assert from "node:assert/strict";import { readFile } from "node:fs/promises";import { fileURLToPath } from "node:url";
const src = fileURLToPath(new URL("../src/", import.meta.url));const css = await readFile(`${src}styles.css`, "utf8");
const ROOT_FONT = 16;
/** * What PLAY and Download need side by side, measured in a browser. Neither * half wraps, so this is a floor rather than a preference: below it the * control overflows its column, which is the bug this file is about. Node * cannot measure text, so a change to either half's type or padding means * re-measuring this. */const LAUNCH_CONTROL = 229;
/** The body of a rule, by its selector. */function rule(selector) { const start = css.indexOf(`\n${selector} {`); assert.notEqual(start, -1, `${selector} moved or was renamed`); const end = css.indexOf("\n}", start); return css.slice(start, end);}
function declaration(body, property, what) { const found = new RegExp(`\\n\\s*${property}:\\s*([^;]+);`).exec(body); assert.ok(found, `${what} moved or was renamed`); return found[1].trim();}
/** A CSS length in px. Only px and rem appear in these rules. */function length(raw, what) { const found = /^([\d.]+)(px|rem)$/.exec(raw.trim()); assert.ok(found, `${what} is ${raw}, which this test cannot measure`); return Number(found[1]) * (found[2] === "rem" ? ROOT_FONT : 1);}
/** The readable column, the gap and the terrain tile, added up. */function needed() { const main = rule(".daily-text-main"); const basis = declaration(main, "flex", ".daily-text-main flex").split(/\s+/); assert.equal( basis.length, 3, ".daily-text-main flex is not grow/shrink/basis", );
const column = length(basis[2], ".daily-text-main flex-basis"); const gap = length( declaration(rule(".daily-text"), "gap", ".daily-text gap"), ".daily-text gap", ); const tile = length( declaration( rule(".daily-terrain-tile"), "width", ".daily-terrain-tile width", ), ".daily-terrain-tile width", ); return { column, gap, tile, total: column + gap + tile };}
test("the readable column can hold the launch control", () => { const { column } = needed(); assert.ok( column >= LAUNCH_CONTROL, `the readable column may be as narrow as ${column}px, and PLAY beside ` + `Download needs about ${LAUNCH_CONTROL}px - the text will run on under ` + `the terrain tile`, );});
test("the card leaves room for the ground beside the text", () => { const { column, gap, tile, total } = needed(); const columns = declaration( rule(".daily"), "grid-template-columns", ".daily grid-template-columns", ); const found = /minmax\((\d+(?:\.\d+)?(?:px|rem)),\s*1fr\)\s*$/.exec(columns); assert.ok( found, `.daily's text column is "${columns}" and has no floor under it: a share ` + `of the card is not enough, which is how the text came to be read ` + `through the terrain tile`, ); const floor = length(found[1], ".daily text column floor"); assert.ok( floor >= total, `.daily gives the text side a floor of ${floor}px, and it holds a ` + `${column}px column, a ${gap}px gap and a ${tile}px tile - ${total}px`, );});
test("nothing readable can outgrow the column it is in", () => { const track = declaration( rule(".daily-text-main"), "grid-template-columns", ".daily-text-main grid-template-columns", ); assert.match( track, /^minmax\(0,/, "an auto track sizes to the launch control, which does not wrap, and the " + "column overflows whatever is beside it", );});
test("the ground still has somewhere to go on a phone", () => { const row = rule(".daily-text"); assert.equal( declaration(row, "display", ".daily-text display"), "flex", ".daily-text is a grid again: its tracks cannot give way, so on a screen " + "too narrow for two columns the text will run on under the tile", ); assert.equal( declaration(row, "flex-wrap", ".daily-text flex-wrap"), "wrap", "without wrapping there is nowhere for the terrain tile to go", );});