Public: anyone can read this; the crew can change it.

The board's panel grid is part of §5's board component: .bgrid and .bp-* move from content.ts into it #4838

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

mason/forge:mason/4833-the-board-s-panel-grid-is-part-of-5-s-bo → main 4 commits fork

  • Merged. mason/4833-the-board-s-panel-grid-is-part-of-5-s-bo was merged into main as c680c94.

Review

Sign in to review this change.
5 files changed +61 −14
docs/design/sections/5-components.md +1 −1
@@ -77,7 +77,7 @@ specification.
7777 | **assignee card** | `.card` with an `.edit-row` form | — | who is on it, then one select and one button for a writer. People first, the crew last and marked `(agent)`, because assigning an agent is what starts it working and the choice is not the same kind of choice | a picker with people, then agents |
7878 | **inbox** (`asks_page.ts`) | one list above the feed | — | _On you_: what asks you and what is assigned to you, one row each, each with what it waits for (`needsYouSection`), and one count in the top bar. Absent when empty: a card saying nothing is a zero drawn | the same two panes on the dashboard |
7979 | **look** (`pages/looks.ts`) | `.look` in a `.looks` strip | `.look[data-slot=phone\|desktop\|thumb\|now]` sizes the frame; `.looks[data-compare]` sets two sides (before · main, then after · the pull) beside each other | a picture always carries its own `width`/`height`, so nothing shifts when it loads; a phone keeps 200px, a desktop takes the rest up to its own size, and under 640px a strip stacks; an attached picture is a `figure` in the strip with its line under it | the picture in the terminal (§6·0c) |
80 | **board** (`pages/board.ts`) | `.board` (`.board-grid`, `.board-region`) | `data-wall` (across the room: no keys, no pointer, larger), `data-focus=working\|landed\|decided\|today` | the one whole-screen layout: four live regions fill a second monitor ≥1100px and each list scrolls on its own, one column below; above the panels only a collapsed one-line `#notes` (`<details>`: closed by default, an open list stays open across live swaps), the strips below them; inside, only §5 parts (list card rows, badges, meters, `kbd`); a swapped region's heading wears `data-fresh` for a moment | four panes, one focused by its number |
80 | **board** (`pages/board.ts`) | `.board` (`.board-grid`, `.board-region`); a board's panels: `.bgrid` (`components.ts`), each panel a `.card` sized `.bp-w2` `.bp-w3` `.bp-h2` `.bp-h3` | `data-wall` (across the room: no keys, no pointer, larger), `data-focus=working\|landed\|decided\|today` | the one whole-screen layout: four live regions fill a second monitor ≥1100px and each list scrolls on its own, one column below; above the panels only a collapsed one-line `#notes` (`<details>`: closed by default, an open list stays open across live swaps), the strips below them; inside, only §5 parts (list card rows, badges, meters, `kbd`); a swapped region's heading wears `data-fresh` for a moment. A saved board's panels (`/boards/<slug>`, the studio's pinned panels) sit in `.bgrid`: three columns, one under 720px, a panel spanning its `w` columns. Its `h` has no rule in components.ts: `.bp-h2` and `.bp-h3` only size the panel's `.chart-box`, from content.ts, the layer `.chart-box` is drawn in, and move here when `.chart-box` does | four panes, one focused by its number |
8181 | **stacked bar chart** `windowSvg()` (`fleet-graph.ts`) | `.plots`, `.plot` (`.plot-name`), `.plot-legend` | bars wear `fg-sN`, the `--series-N` token | server-drawn SVG with `width`/`height` set, so it holds its box before the stylesheet; gridlines `--border`, figures `--muted-fg` in mono, panel names `--faint`; `role="img"` with an `aria-label` totalling it, a `<title>` per bar, and a table of the same numbers beside it | a table of the same numbers |
8282 | **chart** `chartBox()` (`ui.ts`) | `.chart-box` wrapping `drawChart`'s svg `.chart` (`.big` for the headline figure) | `.is-table` for a table panel | one query or series drawn on the server: the svg carries its own `width`/`height` and the box holds its space, so nothing shifts; `role="img"` with an `aria-label` of its title. Reach for it wherever a page draws a `boards/chart.ts` chart — `/system`'s memory pair and every board panel — and size it from the page (`.bp-*`, `.plots`, `.bgrid`), never inside the frame | the same numbers as a table |
8383
docs/design/sections/5d-page-local-classes.md −5
@@ -43,11 +43,6 @@ the same line (#4888).
4343
4444 `.split` is the one two-column page: main, then an `<aside>` rail of 260px that sticks from 960px. `data-rail="wide"` on it (the studio's home and an app's page) widens the rail to 320px from 900px, drops the top margin, and lets the rail scroll with the page, since a column of cards runs taller than a screen
4545 - **`style/content.ts`, page furniture** — what frames a page's content: page and repo heads, the front page and its tiles, explore, backups, boards, the fleet chart's series colours, lineage:
46 - `.bgrid`
47 - `.bp-h2`
48 - `.bp-h3`
49 - `.bp-w2`
50 - `.bp-w3`
5146 - `.commit-body`
5247 - `.commit-head`
5348 - `.filters`
src/web/style/components.ts +7
@@ -832,6 +832,13 @@ details[open] > summary.row > .row-lead { transform: rotate(90deg); }
832832 .empty .btn { margin-top: 8px; }
833833 .card.empty { border-style: dashed; box-shadow: none; }
834834
835 /* ---- board panel grid: a board's panels, on /boards and pinned in the studio ---- */
836 .bgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin-bottom: 16px; }
837 .bp-w2 { grid-column: span 2; }
838 .bp-w3 { grid-column: span 3; }
839 .bgrid h2 { font-size: 14px; }
840 @media (max-width: 720px) { .bgrid { grid-template-columns: minmax(0, 1fr); } .bp-w2, .bp-w3 { grid-column: auto; } }
841
835842 /* ---- settings shell ---- */
836843 .settings { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; margin-top: 16px; }
837844 .settings-nav {
src/web/style/content.ts +5 −8
@@ -181,18 +181,15 @@ a.origin-chip:hover { border-color: var(--border-strong); color: var(--fg); }
181181 .chart-box circle { fill: var(--accent); }
182182 .chart-box .big { fill: var(--fg); font-family: inherit; }
183183 .chart-box.is-table { aspect-ratio: auto; height: 260px; overflow: auto; }
184 /* A board panel sizes its chart from here, after .chart-box: the grid itself
185 is §5's board (components.ts), but this layer is where .chart-box is drawn. */
186 .bgrid .chart-box { max-width: none; }
187 .bp-h2 .chart-box { aspect-ratio: 720 / 400; }
188 .bp-h3 .chart-box { aspect-ratio: 720 / 540; }
184189 .bp-h2 .chart-box.is-table { height: 400px; }
185190 .bp-h3 .chart-box.is-table { height: 540px; }
186191 #summary { display: flex; flex-wrap: wrap; gap: 6px; }
187192 #summary .pill { max-width: 100%; white-space: normal; }
188 .bgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin-bottom: 16px; }
189 .bp-w2 { grid-column: span 2; }
190 .bp-w3 { grid-column: span 3; }
191 .bgrid .chart-box { max-width: none; }
192 .bp-h2 .chart-box { aspect-ratio: 720 / 400; }
193 .bp-h3 .chart-box { aspect-ratio: 720 / 540; }
194 .bgrid h2 { font-size: 14px; }
195 @media (max-width: 720px) { .bgrid { grid-template-columns: minmax(0, 1fr); } .bp-w2, .bp-w3 { grid-column: auto; } }
196193 /* The stacked bar chart's series colours, for its bars (fleet-graph.ts).
197194 Okabe–Ito, told apart with common colour-vision deficiencies; the eighth,
198195 the folded "others", is grey. */
test/board-grid-style.test.ts added +48
@@ -0,0 +1,48 @@
1 /**
2 * #4833: the grid a board's panels sit in is §5's board, so its rules live in
3 * components.ts, once each. What sizes a panel's chart stays in content.ts
4 * after `.chart-box`: layers rank above specificity, so in components it
5 * would lose to `.chart-box`'s own width and ratio.
6 */
7 import { describe, expect, test } from "bun:test";
8 import { css } from "../src/web/style.ts";
9 import { components } from "../src/web/style/components.ts";
10 import { content } from "../src/web/style/content.ts";
11
12 /** How many times `rule` is written in `sheet`. */
13 const count = (sheet: string, rule: string) => sheet.split(rule).length - 1;
14
15 const GRID = [
16 ".bgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin-bottom: 16px; }",
17 ".bp-w2 { grid-column: span 2; }",
18 ".bp-w3 { grid-column: span 3; }",
19 ".bgrid h2 { font-size: 14px; }",
20 "@media (max-width: 720px) { .bgrid { grid-template-columns: minmax(0, 1fr); } .bp-w2, .bp-w3 { grid-column: auto; } }",
21 ];
22
23 const SIZING = [
24 ".bgrid .chart-box { max-width: none; }",
25 ".bp-h2 .chart-box { aspect-ratio: 720 / 400; }",
26 ".bp-h3 .chart-box { aspect-ratio: 720 / 540; }",
27 ".bp-h2 .chart-box.is-table { height: 400px; }",
28 ".bp-h3 .chart-box.is-table { height: 540px; }",
29 ];
30
31 describe("the board's panel grid", () => {
32 test("each grid rule is in the served stylesheet once, from components.ts", () => {
33 for (const rule of GRID) {
34 expect(count(css, rule)).toBe(1);
35 expect(count(components, rule)).toBe(1);
36 expect(count(content, rule)).toBe(0);
37 }
38 });
39
40 test("each panel's chart sizing is served once, from content.ts after .chart-box.is-table", () => {
41 const table = content.indexOf(".chart-box.is-table { aspect-ratio: auto;");
42 expect(table).toBeGreaterThan(-1);
43 for (const rule of SIZING) {
44 expect(count(css, rule)).toBe(1);
45 expect(content.indexOf(rule)).toBeGreaterThan(table);
46 }
47 });
48 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs