Public: anyone can read this; the crew can change it.
docs/DESIGN.md §5d lists one class per line, so retiring one class never conflicts with retiring another #4908
Check · Review · Land · Live done — Landed and live in production.
mason/forge:mason/4888-docs-design-md-5d-lists-one-class-per-li → main 3 commits fork
2 files
changed +235
−10
docs/DESIGN.md +206 −10
| @@ -389,21 +389,217 @@ listed under, and a new page reaches for §5's components instead of | ||
| 389 | 389 | borrowing one. The plan (`docs/design/plan.md`) retires them page by page — |
| 390 | 390 | onto a §5 component, or into the table when a page-local thing turns out to |
| 391 | 391 | be a component — and the check fails a name kept here after its last rule is |
| 392 | gone, so this list only shrinks. | |
| 392 | gone, so this list only shrinks. Each class sits on its own line, so to | |
| 393 | retire a class, delete its line: two pulls retiring two classes never edit | |
| 394 | the same line (#4888). | |
| 395 | ||
| 396 | - **`style/base.ts`** — the page shell (topbar, main, footer) and the layout and text utilities every page leans on: | |
| 397 | - `.bar` | |
| 398 | - `.bare` | |
| 399 | - `.foot` | |
| 400 | - `.grow` | |
| 401 | - `.hide-lg` | |
| 402 | - `.hide-sm` | |
| 403 | - `.js-only` | |
| 404 | - `.mark` | |
| 405 | - `.mb` | |
| 406 | - `.mt` | |
| 407 | - `.muted` | |
| 408 | - `.narrow` | |
| 409 | - `.narrow-wide` | |
| 410 | - `.num` | |
| 411 | - `.reduced` | |
| 412 | - `.shell` | |
| 413 | - `.shell-wide` | |
| 414 | - `.skip` | |
| 415 | - `.small` | |
| 416 | - `.spacer` | |
| 417 | - `.sr-only` | |
| 418 | - `.stack` | |
| 419 | - `.stack-tight` | |
| 420 | - `.topbar` | |
| 421 | - `.topbar-tools` | |
| 422 | - `.truncate` | |
| 423 | - `.wordmark` | |
| 393 | 424 | |
| 394 | - **`style/base.ts`** — the page shell (topbar, main, footer) and the layout and text utilities every page leans on: `.bar` `.bare` `.foot` `.grow` `.hide-lg` `.hide-sm` `.js-only` `.mark` `.mb` `.mt` `.muted` `.narrow` `.narrow-wide` `.num` `.reduced` `.shell` `.shell-wide` `.skip` `.small` `.spacer` `.sr-only` `.stack` `.stack-tight` `.topbar` `.topbar-tools` `.truncate` `.wordmark` | |
| 395 | 425 | A `.field` directly inside a `.bar` drops its bottom margin and the bar aligns to the end, so a labelled input and its button share a baseline |
| 396 | - **`style/components.ts`** — parts of the §5 components that the table does not spell out — the palette's list, the menu's items, a dialog's head and foot, comments, the theme picker — and a few small helpers beside them: `.cat` `.comment` `.comment-body` `.comment-form` `.dialog-body` `.dialog-foot` `.dialog-head` `.empty-title` `.error-note` `.field-row` `.form-actions` `.hex` `.ico` `.ico-loader` `.list` `.menu-item` `.menu-panel` `.menu-sep` `.menu-title` `.palette-empty` `.palette-foot` `.palette-group` `.palette-heading` `.palette-input` `.palette-item` `.palette-list` `.preview` `.sep` `.split` `.sprite` `.swatch` `.table-scroll` `.tell-here` `.theme-apply` `.theme-option` `.tick` `.timeline` `.tl-dot` `.toast-body` `.topbar-search` | |
| 426 | - **`style/components.ts`** — parts of the §5 components that the table does not spell out — the palette's list, the menu's items, a dialog's head and foot, comments, the theme picker — and a few small helpers beside them: | |
| 427 | - `.cat` | |
| 428 | - `.comment` | |
| 429 | - `.comment-body` | |
| 430 | - `.comment-form` | |
| 431 | - `.dialog-body` | |
| 432 | - `.dialog-foot` | |
| 433 | - `.dialog-head` | |
| 434 | - `.empty-title` | |
| 435 | - `.error-note` | |
| 436 | - `.field-row` | |
| 437 | - `.form-actions` | |
| 438 | - `.hex` | |
| 439 | - `.ico` | |
| 440 | - `.ico-loader` | |
| 441 | - `.list` | |
| 442 | - `.menu-item` | |
| 443 | - `.menu-panel` | |
| 444 | - `.menu-sep` | |
| 445 | - `.menu-title` | |
| 446 | - `.palette-empty` | |
| 447 | - `.palette-foot` | |
| 448 | - `.palette-group` | |
| 449 | - `.palette-heading` | |
| 450 | - `.palette-input` | |
| 451 | - `.palette-item` | |
| 452 | - `.palette-list` | |
| 453 | - `.preview` | |
| 454 | - `.sep` | |
| 455 | - `.split` | |
| 456 | - `.sprite` | |
| 457 | - `.swatch` | |
| 458 | - `.table-scroll` | |
| 459 | - `.tell-here` | |
| 460 | - `.theme-apply` | |
| 461 | - `.theme-option` | |
| 462 | - `.tick` | |
| 463 | - `.timeline` | |
| 464 | - `.tl-dot` | |
| 465 | - `.toast-body` | |
| 466 | - `.topbar-search` | |
| 467 | ||
| 397 | 468 | `.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 |
| 398 | - **`style/components.ts`, settings rows** — a list whose rows are settings (limits, capacity): the `<ul class="list setting-list">` lets title and meta wrap instead of ellipsizing, and a row's controls take their own line under 640px. `.row-fields` is the form in that row's trail (input, Save, Default): always visible, never hover-gated, wrapping under the text before it would clip. Use both for any page whose rows show a name, a current value, and a control to change it; use `.row-actions` only for secondary actions (delete, wake, pin, revoke). Flags, telemetry, cloud, people, crew roles and subscription headroom/budget use `.row-fields`. Classes: `.row-fields` `.setting-list` | |
| 399 | - **`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: `.bform` `.bgrid` `.bmanage` `.bp-h2` `.bp-h3` `.bp-w2` `.bp-w3` `.break` `.bt-bar` `.bt-grid` `.bt-group` `.bt-hist` `.bt-name` `.bt-procs` `.bt-row` `.bt-val` `.commit-body` `.commit-head` `.domain-records` `.fg-s0` `.fg-s1` `.fg-s2` `.fg-s3` `.fg-s4` `.fg-s5` `.fg-s6` `.fg-s7` `.filters` `.flag-form` `.front-admin` `.front-crew` `.front-featured` `.front-featured-body` `.front-featured-look` `.front-issues` `.front-live` `.front-more` `.front-pick` `.headroom` `.issue-head` `.issue-meta` `.number` `.owner` `.page-head` `.policy-line` `.qf` `.repo-actions` `.repo-audience` `.repo-desc` `.repo-layout` `.repo-lineage` `.repo-title` `.search` `.slash` `.sub` `.table-wrap` `.tok` `.where-sep` | |
| 400 | - **`style/content.ts`, code view** — the source view and the syntax-highlight token classes `highlight-html.ts` builds as `tok-${kind}`: `.blob-view` `.ln` `.tok-attribute` `.tok-comment` `.tok-constant` `.tok-decorator` `.tok-deleted` `.tok-emphasis` `.tok-function` `.tok-heading` `.tok-inserted` `.tok-keyword` `.tok-link` `.tok-meta` `.tok-number` `.tok-operator` `.tok-plain` `.tok-property` `.tok-punctuation` `.tok-regex` `.tok-string` `.tok-tag` `.tok-type` `.tok-variable` | |
| 401 | - **`style/content.ts`, prose (markdown)** — table cell alignment, built by `markdown.ts` as `ta-${align}`: `.ta-c` `.ta-r` | |
| 402 | - **`style/content.ts`, diff viewer** — the diff table: its gutters, line kinds, file head and inline review comments: `.add` `.del` `.dh` `.diff` `.diff-body` `.diff-head` `.diff-note` `.diff-path` `.diff-stat` `.diff-stub` `.diff-summary` `.diff-table` `.dl` `.dn` `.dn-comment` `.nonl` `.wd` | |
| 469 | - **`style/components.ts`, settings rows** — a list whose rows are settings (limits, capacity): the `<ul class="list setting-list">` lets title and meta wrap instead of ellipsizing, and a row's controls take their own line under 640px. `.row-fields` is the form in that row's trail (input, Save, Default): always visible, never hover-gated, wrapping under the text before it would clip. Use both for any page whose rows show a name, a current value, and a control to change it; use `.row-actions` only for secondary actions (delete, wake, pin, revoke). Flags, telemetry, cloud, people, crew roles and subscription headroom/budget use `.row-fields`. Classes: | |
| 470 | - `.row-fields` | |
| 471 | - `.setting-list` | |
| 472 | - **`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: | |
| 473 | - `.bform` | |
| 474 | - `.bgrid` | |
| 475 | - `.bmanage` | |
| 476 | - `.bp-h2` | |
| 477 | - `.bp-h3` | |
| 478 | - `.bp-w2` | |
| 479 | - `.bp-w3` | |
| 480 | - `.break` | |
| 481 | - `.bt-bar` | |
| 482 | - `.bt-grid` | |
| 483 | - `.bt-group` | |
| 484 | - `.bt-hist` | |
| 485 | - `.bt-name` | |
| 486 | - `.bt-procs` | |
| 487 | - `.bt-row` | |
| 488 | - `.bt-val` | |
| 489 | - `.commit-body` | |
| 490 | - `.commit-head` | |
| 491 | - `.domain-records` | |
| 492 | - `.fg-s0` | |
| 493 | - `.fg-s1` | |
| 494 | - `.fg-s2` | |
| 495 | - `.fg-s3` | |
| 496 | - `.fg-s4` | |
| 497 | - `.fg-s5` | |
| 498 | - `.fg-s6` | |
| 499 | - `.fg-s7` | |
| 500 | - `.filters` | |
| 501 | - `.flag-form` | |
| 502 | - `.front-admin` | |
| 503 | - `.front-crew` | |
| 504 | - `.front-featured` | |
| 505 | - `.front-featured-body` | |
| 506 | - `.front-featured-look` | |
| 507 | - `.front-issues` | |
| 508 | - `.front-live` | |
| 509 | - `.front-more` | |
| 510 | - `.front-pick` | |
| 511 | - `.headroom` | |
| 512 | - `.issue-head` | |
| 513 | - `.issue-meta` | |
| 514 | - `.number` | |
| 515 | - `.owner` | |
| 516 | - `.page-head` | |
| 517 | - `.policy-line` | |
| 518 | - `.qf` | |
| 519 | - `.repo-actions` | |
| 520 | - `.repo-audience` | |
| 521 | - `.repo-desc` | |
| 522 | - `.repo-layout` | |
| 523 | - `.repo-lineage` | |
| 524 | - `.repo-title` | |
| 525 | - `.search` | |
| 526 | - `.slash` | |
| 527 | - `.sub` | |
| 528 | - `.table-wrap` | |
| 529 | - `.tok` | |
| 530 | - `.where-sep` | |
| 531 | - **`style/content.ts`, code view** — the source view and the syntax-highlight token classes `highlight-html.ts` builds as `tok-${kind}`: | |
| 532 | - `.blob-view` | |
| 533 | - `.ln` | |
| 534 | - `.tok-attribute` | |
| 535 | - `.tok-comment` | |
| 536 | - `.tok-constant` | |
| 537 | - `.tok-decorator` | |
| 538 | - `.tok-deleted` | |
| 539 | - `.tok-emphasis` | |
| 540 | - `.tok-function` | |
| 541 | - `.tok-heading` | |
| 542 | - `.tok-inserted` | |
| 543 | - `.tok-keyword` | |
| 544 | - `.tok-link` | |
| 545 | - `.tok-meta` | |
| 546 | - `.tok-number` | |
| 547 | - `.tok-operator` | |
| 548 | - `.tok-plain` | |
| 549 | - `.tok-property` | |
| 550 | - `.tok-punctuation` | |
| 551 | - `.tok-regex` | |
| 552 | - `.tok-string` | |
| 553 | - `.tok-tag` | |
| 554 | - `.tok-type` | |
| 555 | - `.tok-variable` | |
| 556 | - **`style/content.ts`, prose (markdown)** — table cell alignment, built by `markdown.ts` as `ta-${align}`: | |
| 557 | - `.ta-c` | |
| 558 | - `.ta-r` | |
| 559 | - **`style/content.ts`, diff viewer** — the diff table: its gutters, line kinds, file head and inline review comments: | |
| 560 | - `.add` | |
| 561 | - `.del` | |
| 562 | - `.dh` | |
| 563 | - `.diff` | |
| 564 | - `.diff-body` | |
| 565 | - `.diff-head` | |
| 566 | - `.diff-note` | |
| 567 | - `.diff-path` | |
| 568 | - `.diff-stat` | |
| 569 | - `.diff-stub` | |
| 570 | - `.diff-summary` | |
| 571 | - `.diff-table` | |
| 572 | - `.dl` | |
| 573 | - `.dn` | |
| 574 | - `.dn-comment` | |
| 575 | - `.nonl` | |
| 576 | - `.wd` | |
| 403 | 577 | - **`style/content.ts`, apps, runs, and the crew** — run pages, their logs and checks (a pull's look is §5's **look**). |
| 404 | 578 | - **`pages/board.ts`** — the board itself is §5's **board**; the spend tables `spend.ts` draws wear §5's `.table` and `.stack`, no class of their own |
| 405 | - **`pages/map.ts`** — the map of what waits for what: `.map-ask` `.map-breath` `.map-canvas` `.map-card` `.map-dot` `.map-edge` `.map-edge-crit` `.map-edge-done` `.map-main` `.map-meta` `.map-node` `.map-rule` `.map-svg` `.map-title` `.map-tool` `.map-who` `.map-who-i` `.map-who-n` `.map-word` `.map-wrap` | |
| 406 | - **`studio/feed_style.ts`** — the home feed's cards and its composer (the apps rail is §5's card, row and btn; an admin's tick boxes and Archive are always shown, deliberately, with no Select toggle): `.feed` `.feed-head` | |
| 579 | - **`pages/map.ts`** — the map of what waits for what: | |
| 580 | - `.map-ask` | |
| 581 | - `.map-breath` | |
| 582 | - `.map-canvas` | |
| 583 | - `.map-card` | |
| 584 | - `.map-dot` | |
| 585 | - `.map-edge` | |
| 586 | - `.map-edge-crit` | |
| 587 | - `.map-edge-done` | |
| 588 | - `.map-main` | |
| 589 | - `.map-meta` | |
| 590 | - `.map-node` | |
| 591 | - `.map-rule` | |
| 592 | - `.map-svg` | |
| 593 | - `.map-title` | |
| 594 | - `.map-tool` | |
| 595 | - `.map-who` | |
| 596 | - `.map-who-i` | |
| 597 | - `.map-who-n` | |
| 598 | - `.map-word` | |
| 599 | - `.map-wrap` | |
| 600 | - **`studio/feed_style.ts`** — the home feed's cards and its composer (the apps rail is §5's card, row and btn; an admin's tick boxes and Archive are always shown, deliberately, with no Select toggle): | |
| 601 | - `.feed` | |
| 602 | - `.feed-head` | |
| 407 | 603 | --- |
| 408 | 604 | |
| 409 | 605 | ## 6. Keyboard |
test/design-lint.test.ts +29
| @@ -72,6 +72,35 @@ describe("design check: nothing added outside the system (#2678)", () => { | ||
| 72 | 72 | expect(documentedClasses("## 4. Space\n`.a`")).toEqual([]); |
| 73 | 73 | }); |
| 74 | 74 | |
| 75 | test("§5d's one-class-per-line sub-list reads as the same set as the inline run (#4888)", () => { | |
| 76 | const inline = [ | |
| 77 | "## 5. The component vocabulary", | |
| 78 | "### 5d. Page-local classes", | |
| 79 | "- **`style/base.ts`** — the shell: `.bar` `.bare` `.foot`", | |
| 80 | " A `.field` inside a `.bar` drops its margin", | |
| 81 | "- **`pages/x.ts`** — the x page. Classes: `.x-card` `.x-row`", | |
| 82 | "## 6. Keyboard", | |
| 83 | ].join("\n"); | |
| 84 | const listed = [ | |
| 85 | "## 5. The component vocabulary", | |
| 86 | "### 5d. Page-local classes", | |
| 87 | "- **`style/base.ts`** — the shell:", | |
| 88 | " - `.bar`", | |
| 89 | " - `.bare`", | |
| 90 | " - `.foot`", | |
| 91 | "", | |
| 92 | " A `.field` inside a `.bar` drops its margin", | |
| 93 | "- **`pages/x.ts`** — the x page. Classes:", | |
| 94 | " - `.x-card`", | |
| 95 | " - `.x-row`", | |
| 96 | "## 6. Keyboard", | |
| 97 | ].join("\n"); | |
| 98 | const fixed = ["bar", "bare", "field", "foot", "x-card", "x-row"]; | |
| 99 | expect(registeredClasses(inline)).toEqual(fixed); | |
| 100 | expect(registeredClasses(listed)).toEqual(fixed); | |
| 101 | expect(documentedClasses(listed)).toEqual(fixed); | |
| 102 | }); | |
| 103 | ||
| 75 | 104 | test("fails a pull that adds a colour, a size or a component", () => { |
| 76 | 105 | const base = { files: { "src/web/x.ts": { colour: 1, size: 1 } } }; |
| 77 | 106 | const now = { ...base, classes: ["btn", "run-log", "x-card", "x-row", "x-wrapped"] }; |
new above
offline