Public: anyone can read this; the crew can change it.
Design: the make-it-yours page's key and value list uses the design system, and kv leaves §5d #3896
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/3848-design-the-make-it-yours-page-s-key-and → main 8 commits fork 3 threads · 3 unresolved
5 files
changed +38
−37
docs/DESIGN.md +1 −1
| @@ -393,7 +393,7 @@ gone, so this list only shrinks. | ||
| 393 | 393 | - **`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` `.live-pill` `.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` |
| 394 | 394 | - **`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` `.clone` `.clone-text` `.comment` `.comment-body` `.comment-form` `.dash` `.dialog-body` `.dialog-foot` `.dialog-head` `.empty-title` `.error-note` `.field-row` `.form-actions` `.hex` `.ico` `.ico-loader` `.list` `.live-status` `.menu-item` `.menu-panel` `.menu-sep` `.menu-title` `.palette-empty` `.palette-foot` `.palette-group` `.palette-heading` `.palette-input` `.palette-item` `.palette-list` `.passkey` `.passkey-lead` `.passkey-note` `.passkey-off` `.passkey-on` `.preview` `.sep` `.split` `.sprite` `.swatch` `.table-scroll` `.tell-here` `.theme-apply` `.theme-option` `.tick` `.timeline` `.tl-dot` `.toast-body` `.topbar-search` |
| 395 | 395 | - **`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` |
| 396 | - **`style/content.ts`, page furniture** — what frames a page's content: page and repo heads, the merge box, the front page and its tiles, explore, backups, boards, the fleet chart's series colours, following, lineage: `.about` `.act` `.app-shelf` `.app-tile` `.app-tile-body` `.app-tile-desc` `.app-tile-look` `.app-tile-name` `.backups-drill` `.backups-error` `.backups-now` `.backups-restore` `.bform` `.bgrid` `.big` `.bmanage` `.boards-result` `.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` `.chart` `.chart-box` `.commit-body` `.commit-head` `.connect-more` `.connect-path` `.domain-records` `.explore-filters` `.explore-line` `.explore-main` `.explore-name` `.explore-row` `.fg-s0` `.fg-s1` `.fg-s2` `.fg-s3` `.fg-s4` `.fg-s5` `.fg-s6` `.fg-s7` `.filters` `.flag-form` `.following` `.following-actions` `.following-eyebrow` `.following-foot` `.following-head` `.following-sentence` `.fork-bar` `.front-admin` `.front-controls` `.front-crew` `.front-featured` `.front-featured-body` `.front-featured-look` `.front-issues` `.front-live` `.front-more` `.front-pick` `.front-pin-any` `.front-weights` `.frozen` `.frozen-form` `.frozen-sentence` `.handoff` `.handoff-links` `.headroom` `.hero` `.hero-terminal` `.issue-head` `.issue-meta` `.kv` `.lineage` `.lineage-children` `.lineage-here` `.merge-box` `.merge-form` `.merge-headline` `.merge-sub` `.mirror-form` `.number` `.origin-link` `.origin-mark` `.origin-name` `.origin-row` `.owner` `.page-head` `.path-head` `.policy-line` `.qf` `.repo-actions` `.repo-audience` `.repo-desc` `.repo-layout` `.repo-lineage` `.repo-title` `.search` `.slash` `.stage-detail` `.stage-dot` `.steps` `.sub` `.sys-pair` `.table-wrap` `.terminal-line` `.tok` `.tree-row` `.tree-total` `.wall-cells` `.where-sep` | |
| 396 | - **`style/content.ts`, page furniture** — what frames a page's content: page and repo heads, the merge box, the front page and its tiles, explore, backups, boards, the fleet chart's series colours, following, lineage: `.about` `.act` `.app-shelf` `.app-tile` `.app-tile-body` `.app-tile-desc` `.app-tile-look` `.app-tile-name` `.backups-drill` `.backups-error` `.backups-now` `.backups-restore` `.bform` `.bgrid` `.big` `.bmanage` `.boards-result` `.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` `.chart` `.chart-box` `.commit-body` `.commit-head` `.connect-more` `.connect-path` `.domain-records` `.explore-filters` `.explore-line` `.explore-main` `.explore-name` `.explore-row` `.fg-s0` `.fg-s1` `.fg-s2` `.fg-s3` `.fg-s4` `.fg-s5` `.fg-s6` `.fg-s7` `.filters` `.flag-form` `.following` `.following-actions` `.following-eyebrow` `.following-foot` `.following-head` `.following-sentence` `.fork-bar` `.front-admin` `.front-controls` `.front-crew` `.front-featured` `.front-featured-body` `.front-featured-look` `.front-issues` `.front-live` `.front-more` `.front-pick` `.front-pin-any` `.front-weights` `.frozen` `.frozen-form` `.frozen-sentence` `.handoff` `.handoff-links` `.headroom` `.hero` `.hero-terminal` `.issue-head` `.issue-meta` `.lineage` `.lineage-children` `.lineage-here` `.merge-box` `.merge-form` `.merge-headline` `.merge-sub` `.mirror-form` `.number` `.origin-link` `.origin-mark` `.origin-name` `.origin-row` `.owner` `.page-head` `.path-head` `.policy-line` `.qf` `.repo-actions` `.repo-audience` `.repo-desc` `.repo-layout` `.repo-lineage` `.repo-title` `.search` `.slash` `.stage-detail` `.stage-dot` `.steps` `.sub` `.sys-pair` `.table-wrap` `.terminal-line` `.tok` `.tree-row` `.tree-total` `.wall-cells` `.where-sep` | |
| 397 | 397 | - **`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` |
| 398 | 398 | - **`style/content.ts`, prose (markdown)** — table cell alignment, built by `markdown.ts` as `ta-${align}`: `.ta-c` `.ta-r` |
| 399 | 399 | - **`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` `.dl-review` `.dn` `.dn-comment` `.nonl` `.rc-hidden` `.rc-resolve` `.rc-resolved` `.wd` |
src/web/studio/make_it_yours.ts +33 −32
| @@ -17,7 +17,7 @@ import { | ||
| 17 | 17 | import { field, readForm } from "../form.ts"; |
| 18 | 18 | import { html, when } from "../html.ts"; |
| 19 | 19 | import { flashTo, page, redirect } from "../layout.ts"; |
| 20 | import { btn, card } from "../ui.ts"; | |
| 20 | import { btn, card, row } from "../ui.ts"; | |
| 21 | 21 | import { NOT_A_MEMBER } from "../../core/roles.ts"; |
| 22 | 22 | import { |
| 23 | 23 | notePhase, |
| @@ -69,47 +69,48 @@ export async function makeItYoursPage(ctx: Ctx): Promise<Response> { | ||
| 69 | 69 | action="${repoBase(repo)}/make-it-yours" |
| 70 | 70 | class="stack" |
| 71 | 71 | > |
| 72 | <dl class="kv"> | |
| 73 | <dt>Yours as</dt> | |
| 74 | <dd class="mono">${p.repo}</dd> | |
| 75 | <dt>Its address</dt> | |
| 76 | <dd class="mono">${p.slug}</dd> | |
| 77 | <dt>Copied</dt> | |
| 78 | <dd>${p.copied.join(", ")}</dd> | |
| 79 | <dt>Not copied</dt> | |
| 80 | <dd> | |
| 81 | ${p.notCopied.join(", ")} — they stay ${p.from.split("/")[0]}'s; | |
| 82 | yours starts empty. | |
| 83 | </dd> | |
| 84 | <dt>Follows</dt> | |
| 85 | <dd> | |
| 86 | ${p.from}: it moves with the original until you change it, and tells | |
| 87 | you when it cannot. | |
| 88 | </dd> | |
| 72 | <ul class="list setting-list"> | |
| 73 | ${row({ title: "Yours as", trail: html`<span class="mono">${p.repo}</span>` })} | |
| 74 | ${row({ title: "Its address", trail: html`<span class="mono">${p.slug}</span>` })} | |
| 75 | ${row({ title: "Copied", meta: html`${p.copied.join(", ")}` })} | |
| 76 | ${row({ | |
| 77 | title: "Not copied", | |
| 78 | meta: html`${p.notCopied.join(", ")} — they stay | |
| 79 | ${p.from.split("/")[0]}'s; yours starts empty.`, | |
| 80 | })} | |
| 81 | ${row({ | |
| 82 | title: "Follows", | |
| 83 | meta: html`${p.from}: it moves with the original until you change | |
| 84 | it, and tells you when it cannot.`, | |
| 85 | })} | |
| 89 | 86 | ${p.existing |
| 90 | ? html`<dt>Who sees it</dt> | |
| 91 | <dd>${p.visibility === "public" ? "anyone" : "you"}</dd>` | |
| 92 | : html`<dt>Who sees it</dt> | |
| 93 | <dd class="stack stack-tight"> | |
| 94 | <label | |
| 87 | ? row({ | |
| 88 | title: "Who sees it", | |
| 89 | trail: html`${p.visibility === "public" ? "anyone" : "you"}`, | |
| 90 | }) | |
| 91 | : html`${row({ | |
| 92 | title: "Who sees it", | |
| 93 | trail: html`<span class="row-fields" role="radiogroup" aria-label="Who sees it" | |
| 94 | ><label class="check" | |
| 95 | 95 | ><input type="radio" name="visibility" value="private" checked /> |
| 96 | 96 | Only you, until you open it up</label |
Radio group has no accessible name. Wrap it in a fieldset with a legend of 'Who sees it', or add role=radiogroup and aria-label. |
||
| 97 | 97 | > |
| 98 | 98 | ${when( |
| 99 | 99 | repo.visibility === "public", |
| 100 | 100 | () => |
| 101 | html`<label | |
| 101 | html`<label class="check" | |
| 102 | 102 | ><input type="radio" name="visibility" value="public" /> |
| 103 | 103 | Anyone, from the start</label |
| 104 | 104 | >`, |
| 105 | )} | |
| 106 | </dd> | |
| 107 | <dt>Today</dt> | |
| 108 | <dd> | |
| 109 | ${p.copiesLeft} more cop${p.copiesLeft === 1 ? "y" : "ies"} you | |
| 110 | can make in the next day | |
| 111 | </dd>`} | |
| 112 | </dl> | |
| 105 | )}</span | |
| 106 | >`, | |
| 107 | })} | |
| 108 | ${row({ | |
| 109 | title: "Today", | |
| 110 | meta: html`${p.copiesLeft} more cop${p.copiesLeft === 1 ? "y" : "ies"} | |
| 111 | you can make in the next day`, | |
| 112 | })}`} | |
| 113 | </ul> | |
| 113 | 114 | <div class="form-actions"> |
| 114 | 115 | ${btn(p.existing ? "Open mine" : "Make it yours", { |
| 115 | 116 | variant: "primary", |
src/web/style/components.ts +1
| @@ -423,6 +423,7 @@ details[open] > summary.row > .row-lead { transform: rotate(90deg); } | ||
| 423 | 423 | they wrap under the text before they would clip, at any width. */ |
| 424 | 424 | .row-fields { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; } |
| 425 | 425 | .row-fields .input { min-width: 0; max-width: 100%; } |
outdated
Specificity beats the |
||
| 426 | .row-fields .check { align-items: center; } | |
| 426 | 427 | .setting-list .row { flex-wrap: wrap; align-items: flex-start; } |
| 427 | 428 | .setting-list .row-main { flex: 1 1 18rem; } |
| 428 | 429 | .setting-list .row-title, .setting-list .row-meta { white-space: normal; overflow: visible; overflow-wrap: anywhere; } |
src/web/style/content.ts −4
| @@ -228,10 +228,6 @@ a.origin-chip:hover { border-color: var(--border-strong); color: var(--fg); } | ||
| 228 | 228 | .repo-layout { grid-template-columns: minmax(0, 1fr) 280px; gap: 24px; } |
| 229 | 229 | .repo-layout > .about { position: sticky; top: calc(var(--topbar-h) + 16px); } |
| 230 | 230 | } |
| 231 | /* Make it yours: what is copied and what is not, read before saying yes. */ | |
| 232 | .kv { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 6px 14px; margin: 0; } | |
| 233 | .kv dt { color: var(--muted-fg); } | |
| 234 | .kv dd { margin: 0; overflow-wrap: anywhere; } | |
| 235 | 231 | .about dl { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; font-size: 13px; margin: 0; } |
| 236 | 232 | .about dt { color: var(--muted-fg); } |
| 237 | 233 | .about dd { margin: 0; min-width: 0; overflow-wrap: anywhere; } |
test/make-it-yours.test.ts +3
| @@ -132,6 +132,9 @@ describe("make it yours", () => { | ||
| 132 | 132 | expect(page).toContain("Make it yours"); |
| 133 | 133 | expect(page).toContain("bob/garden"); |
| 134 | 134 | expect(page).toContain("its variables and secrets"); |
| 135 | expect(page).not.toMatch(/class="kv"|<dl/); | |
| 136 | expect(page).toContain('name="visibility"'); | |
| 137 | expect(page).toContain('role="radiogroup" aria-label="Who sees it"'); | |
| 135 | 138 | // An ro token may plan, never make; a stranger neither; the owner has it. |
| 136 | 139 | expect( |
| 137 | 140 | ( |
new above
offline
The visibility radios are inside
row-meta: muted, 12.5px, withwhite-space: nowrapand overflow hidden from.row-meta, which the.setting-listoverride only partly undoes. The control is the page's decision, so move it totrailin a.row-fieldswrapper, or use a fieldset with a legend. The radio labels then get normal body size and a thumb-sized target.