| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -45,12 +45,16 @@ Two observations worth stating plainly, because they explain almost everything: | |||
| 45 | 45 | ||
| 46 | 46 | ### D1 — Constrain the measure. This is the single biggest lever. | |
| 47 | 47 | ||
| 48 | - `max-width` on the prose column, centred, with the container still full-bleed so cards, code blocks | ||
| 49 | - and the composer keep their current behaviour. | ||
| 48 | + `max-width` on the prose column, centred, with the container still full-bleed so cards and code blocks | ||
| 49 | + keep their current behaviour. *(D9 later brought the composer into the same column; T1 shipped with it | ||
| 50 | + still full-bleed.)* | ||
| 50 | 51 | ||
| 51 | - **Target 680px** — measured, not estimated. An earlier draft of this section said "~72ch, which lands | ||
| 52 | - near 640–700px". Both halves were wrong, and the correction is worth keeping because the mistake is | ||
| 53 | - easy to repeat: | ||
| 52 | + **Target 820px**. T1 shipped 680px, derived from first principles below. That number was later | ||
| 53 | + overruled by the reference itself — see the revision at the end of this decision. The derivation is | ||
| 54 | + kept because its correction is the reusable part; the figure it produced is not. | ||
| 55 | + | ||
| 56 | + An earlier draft of this section said "~72ch, which lands near 640–700px". Both halves were wrong, and | ||
| 57 | + that correction is worth keeping because the mistake is easy to repeat: | ||
| 54 | 58 | ||
| 55 | 59 | | measured in the shipped font at 13px | | | |
| 56 | 60 | | --- | --- | | |
@@ -62,9 +66,21 @@ characters would be a 422px column, narrower than the sidebar. The print-typogra | |||
| 62 | 66 | characters does not transfer to a technical chat: it assumes prose without identifiers, file paths or | |
| 63 | 67 | code, and a 422px column would wrap every code block constantly. | |
| 64 | 68 | ||
| 65 | - 680px is chosen against the measurement: **~116 characters at 13px**, down from 154 at editor width, | ||
| 66 | - while staying wide enough that a fenced block is still readable. When T2 raises the prose size the | ||
| 67 | - same cap tightens to ~108 characters, which is the right direction. | ||
| 69 | + 680px was chosen against that measurement: ~116 characters at 13px, down from 154 at editor width, | ||
| 70 | + while staying wide enough that a fenced block is still readable. | ||
| 71 | + | ||
| 72 | + **Revised to 820px after comparing against the reference directly.** Side-by-side at the same window | ||
| 73 | + width, the Claude Code console's column is **~815px** against our 680 — it uses about half the | ||
| 74 | + available width where we used 41%. The user's report was "the content space is too narrow", and on a | ||
| 75 | + design parameter chosen from first principles versus the artefact we are explicitly trying to match, | ||
| 76 | + the artefact wins. | ||
| 77 | + | ||
| 78 | + Stated honestly: 820px is **~130 characters** at the shipped 14px prose size, which is well outside the | ||
| 79 | + print range this decision already argues does not transfer. Two things make that acceptable rather than | ||
| 80 | + sloppy — the reference demonstrably reads well at that width, and this column carries tables, file | ||
| 81 | + paths and fenced code, none of which wrap gracefully at 680. The risk section's "screenshots are not | ||
| 82 | + measurements" caveat applies: ~815px is read off a screenshot, so 820 is a round number near a | ||
| 83 | + measured one, not a precise transcription. | ||
| 68 | 84 | ||
| 69 | 85 | The elegant part: **in the sidebar this is a no-op.** The container is already narrower than the cap, | |
| 70 | 86 | so nothing moves for existing users. It only takes effect in the editor tab, which is exactly the | |
@@ -196,6 +212,40 @@ Measured in headless Chrome at a 680px column, against `develop`: | |||
| 196 | 212 | Tint stays as the secondary cue rather than being removed: side alone would fail on any surface that | |
| 197 | 213 | reflows the log to a single column. | |
| 198 | 214 | ||
| 215 | + ### D9 — One column for the whole panel, not just the transcript. | ||
| 216 | + | ||
| 217 | + T1 bounded the **transcript** and nothing else. `#composer`, `#status` and the four notice bars are | ||
| 218 | + siblings of `#log`, not children, so none of them saw the cap: at editor width the input was a | ||
| 219 | + **~1580px box sitting under an 820px conversation**. Side by side with the reference — where the | ||
| 220 | + composer sits directly under the text it answers — this was the single most obvious difference left, | ||
| 221 | + more than any type choice. | ||
| 222 | + | ||
| 223 | + **The measure moves from `#log` to `body`.** This is the load-bearing part, not tidying. A custom | ||
| 224 | + property declared on the log is invisible to the log's siblings, which is precisely how the split | ||
| 225 | + arose. On `body`, every element in the shell resolves the same value. | ||
| 226 | + | ||
| 227 | + Two consequences that are easy to miss: | ||
| 228 | + | ||
| 229 | + - **`--shell-x`.** The shell insets by `calc(100% - 2 * var(--shell-x))`, the same value `#log` pads | ||
| 230 | + with, rather than a bare `width: 100%`. Without it the edges agree only where the cap binds, and | ||
| 231 | + out-dent by the log's padding everywhere else — including every sidebar, which is the width most | ||
| 232 | + users are actually in. | ||
| 233 | + - **The runtime override moves too.** `chat.proseWidth` used to be written onto `#log`. Left there it | ||
| 234 | + would resize the conversation and leave the composer on the stylesheet default — reopening this exact | ||
| 235 | + split, but only for users who set the setting, which is the worst place for it to hide. | ||
| 236 | + | ||
| 237 | + Verified in headless Chrome at four widths. Composer and prose edges, left and right: | ||
| 238 | + | ||
| 239 | + | viewport | before (prose / composer) | after | | ||
| 240 | + | --- | --- | --- | | ||
| 241 | + | 1600px | 680 / **1584** — 452px out-dent per side | 820 / 820 — **Δ 0.0** | | ||
| 242 | + | 900px | 680 / 884 | 820 / 820 — **Δ 0.0** | | ||
| 243 | + | 800px | 680 / 784 | 752 / 752 — **Δ 0.0** | | ||
| 244 | + | 420px (sidebar) | 476 / 484 | 476 / 476 — **Δ 0.0** | | ||
| 245 | + | ||
| 246 | + The 420px row is the argument for `--shell-x` on its own: the sidebar was misaligned by 4px a side | ||
| 247 | + before this, quietly, in the surface almost everyone uses. | ||
| 248 | + | ||
| 199 | 249 | --- | |
| 200 | 250 | ||
| 201 | 251 | ## 3. Slices | |
@@ -226,6 +276,11 @@ left and full-measure. **Exit:** a short turn renders as a short right-flush bub | |||
| 226 | 276 | below the column, the assistant is untouched, and the prose inside the bubble is still left-aligned — | |
| 227 | 277 | all four measured, not eyeballed. | |
| 228 | 278 | ||
| 279 | + **T7 — the shell column** *(S)*. D9, plus D1's revision to 820px. Ships: the measure moves to `body`, | ||
| 280 | + `--shell-x`, the shell rule over the composer/status/notice bars, and the runtime override retargeted. | ||
| 281 | + **Exit:** composer and prose edges agree to **0.0px at 1600 / 900 / 800 / 420**, and `chat.proseWidth` | ||
| 282 | + moves both together — measured, not eyeballed. | ||
| 283 | + | ||
| 229 | 284 | **T5 — the escape hatch** *(S)*. D7. **Folded into T2 and shipped with it.** Sequencing it last was a | |
| 230 | 285 | mistake: T2 is the one slice that changes what every existing user sees, and shipping a divisive | |
| 231 | 286 | change with no way back is worse than not shipping it. The plumbing is also shared — once one custom | |
@@ -234,10 +289,12 @@ property reaches the webview from settings, the second is a line — so splittin | |||
| 234 | 289 | Sequencing: T1 first and alone — it may turn out to be most of the perceived fix, and shipping it | |
| 235 | 290 | by itself is the cheapest way to find out before spending effort on T2–T4. | |
| 236 | 291 | ||
| 237 | - That held up: T1–T2, T4 and T6 have shipped in that order, each visible on its own. **T3 is the only | ||
| 238 | - slice of this plan still outstanding.** D8/T6 was not in the original decomposition — it came from | ||
| 239 | - looking at the reference again after T4, which is the argument for shipping slices small enough to | ||
| 240 | - look at. | ||
| 292 | + That held up: T1–T2, T4, T6 and T7 have shipped in that order, each visible on its own. **T3 is the | ||
| 293 | + only slice of this plan still outstanding.** Neither D8/T6 nor D9/T7 was in the original decomposition | ||
| 294 | + — both came from looking at the reference again after shipping, which is the argument for slices small | ||
| 295 | + enough to look at. D9 in particular was invisible from inside the plan: T1's own wording said the | ||
| 296 | + composer "keeps its current behaviour", and it took a side-by-side screenshot to notice that was the | ||
| 297 | + bug rather than the scope. | ||
| 241 | 298 | ||
| 242 | 299 | --- | |
| 243 | 300 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -22,13 +22,16 @@ | |||
| 22 | 22 | color: var(--vscode-foreground); | |
| 23 | 23 | background: transparent; | |
| 24 | 24 | display: flex; flex-direction: column; height: 100vh; | |
| 25 | - } | ||
| 26 | 25 | ||
| 27 | - /* ---- conversation log ---- */ | ||
| 28 | - #log { flex: 1; overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 12px; | ||
| 29 | - /* T1 (docs/CHAT-TYPOGRAPHY.md D1) — the reading measure. A custom property so T5 can hand it to a | ||
| 30 | - setting later without touching the rules below. */ | ||
| 31 | - --prose-max: 680px; | ||
| 26 | + /* T7 (docs/CHAT-TYPOGRAPHY.md D9) — THE SHELL COLUMN. These three live on `body`, not on `#log`, | ||
| 27 | + because the measure is a property of the whole panel: the transcript, the composer and the status | ||
| 28 | + row are all children of `body`, and they have to resolve the SAME value or they cannot line up. | ||
| 29 | + Declared on `#log` (where T1 put them) only the transcript could see them, which is exactly how | ||
| 30 | + the composer ended up spanning the full panel while the prose sat in a 680px column. */ | ||
| 31 | + --prose-max: 820px; | ||
| 32 | + /* The horizontal inset shared by the log's padding and the shell column's width, so the composer's | ||
| 33 | + left edge lands ON the prose's left edge at every width rather than only where the cap binds. */ | ||
| 34 | + --shell-x: 12px; | ||
| 32 | 35 | /* T2 (D2) — the READING type. `--vscode-font-size` is the size of menu labels and tree rows: right | |
| 33 | 36 | for chrome, wrong for three paragraphs of explanation. Message bodies alone get their own size | |
| 34 | 37 | and leading; every control around them keeps inheriting the workbench, so the panel still | |
@@ -39,7 +42,28 @@ | |||
| 39 | 42 | the wrong way. At the default 13px this still resolves to 14px, so nothing moves for anyone who | |
| 40 | 43 | has not changed it. */ | |
| 41 | 44 | --prose-size: calc(var(--vscode-font-size, 13px) + 1px); | |
| 42 | - --prose-leading: 1.65; } | ||
| 45 | + --prose-leading: 1.65; | ||
| 46 | + } | ||
| 47 | + @media (min-width: 760px) { body { --shell-x: 24px; } } | ||
| 48 | + | ||
| 49 | + /* Everything below the log shares the transcript's column: same width, same centre, same edges. | ||
| 50 | + Before this each one spanned the whole panel, so at editor width the composer was a 1600px box | ||
| 51 | + under a 680px conversation — the single thing that most made the panel look unlike the reference, | ||
| 52 | + where the input sits directly under the text it answers. | ||
| 53 | + `calc(100% - 2 * --shell-x)` rather than a bare `width: 100%` + margin: without it these boxes | ||
| 54 | + would out-dent the transcript by the log's padding in every panel narrower than the cap, which is | ||
| 55 | + most sidebars. Overlays are `position: fixed` and deliberately excluded. */ | ||
| 56 | + #bgTasksBar, #ctxBar, #planBar, #reviewBar, #workbar, #composer, #status { | ||
| 57 | + width: calc(100% - 2 * var(--shell-x)); | ||
| 58 | + max-width: var(--prose-max); | ||
| 59 | + margin-inline: auto; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + /* ---- conversation log ---- */ | ||
| 63 | + /* The measure, the type and the inset are all declared on `body` (see above) so the composer and the | ||
| 64 | + status row resolve the same values the transcript does. `--shell-x` is the log's horizontal padding | ||
| 65 | + AND the shell column's inset, which is what keeps the two edges on the same line. */ | ||
| 66 | + #log { flex: 1; overflow-y: auto; padding: 12px var(--shell-x); display: flex; flex-direction: column; gap: 12px; } | ||
| 43 | 67 | /* Log is a flex column → children default to flex-shrink:1. Any child with overflow:hidden (e.g. the | |
| 44 | 68 | approval/edit cards) then gets an auto min-size of 0 and the flex algorithm crushes it to an invisible | |
| 45 | 69 | line once the log overflows. Pin every child to its natural height; the log itself scrolls instead. */ | |
@@ -48,12 +72,15 @@ | |||
| 48 | 72 | in this file are all cards, dialogs and the empty state. In a 380px sidebar the container bounded | |
| 49 | 73 | it, so it never looked wrong — but the chat can now open as an editor tab (AI: Open Chat in | |
| 50 | 74 | Editor), and at 900px the same CSS produced ~154-character lines. | |
| 51 | - Measured in the shipped font at 13px: the average prose character is 5.86px, so 680px is ~116 | ||
| 52 | - characters — a real improvement while staying wide enough that a fenced code block does not wrap | ||
| 53 | - constantly. NOT expressed in `ch`: `0` is 8.13px here, 39% wider than average text, so a `ch` cap | ||
| 54 | - silently overshoots by about a third. | ||
| 75 | + The cap itself is `--prose-max`, declared on `body`, and is deliberately NOT restated here. This | ||
| 76 | + comment carried its own copy of the number and said 680 for exactly as long as it took the cap to | ||
| 77 | + become 820 — which is what a second copy of a value is always for. docs/CHAT-TYPOGRAPHY.md D1 has | ||
| 78 | + how it was chosen; webviewCss.test.js fails if this comment starts quoting a length again. | ||
| 79 | + NOT expressed in `ch`: `0` measures 8.13px against an average prose character of 5.86px, so a | ||
| 80 | + `ch` cap silently overshoots by about a third. Those two figures stay because they are facts about | ||
| 81 | + the typeface, not a decision that can be revised. | ||
| 55 | 82 | Applied to EVERY direct child, not just .msg, so messages, cards and the activity timeline share | |
| 56 | - one column instead of drifting apart at width. Below 680px this is inert — which is why the | ||
| 83 | + one column instead of drifting apart at width. Below the cap this is inert — which is why the | ||
| 57 | 84 | sidebar is untouched. */ | |
| 58 | 85 | #log > * { width: 100%; max-width: var(--prose-max); margin-inline: auto; box-sizing: border-box; } | |
| 59 | 86 | /* ---- per-response copy button (hover-reveal under a completed assistant message) ---- */ | |
@@ -174,7 +201,7 @@ | |||
| 174 | 201 | opens the editor tab sees nothing move. `min-width` here is the WEBVIEW's own width — the iframe | |
| 175 | 202 | is sized to the panel, which is why the existing #empty/dialog rules already use vw/vh. */ | |
| 176 | 203 | @media (min-width: 760px) { | |
| 177 | - #log { padding: 20px 24px; gap: 1.15em; } | ||
| 204 | + #log { padding: 20px var(--shell-x); gap: 1.15em; } | ||
| 178 | 205 | .msg .body p { margin-bottom: 1em; } | |
| 179 | 206 | .msg .body ul, .msg .body ol { margin-bottom: 1em; } | |
| 180 | 207 | /* More space ABOVE a heading than below it, so it binds to the section it introduces rather than | |
@@ -745,7 +772,7 @@ | |||
| 745 | 772 | ||
| 746 | 773 | /* ---- composer ---- */ | |
| 747 | 774 | #composer { | |
| 748 | - margin: 8px; padding: 8px 8px 6px; | ||
| 775 | + margin: 8px auto; padding: 8px 8px 6px; | ||
| 749 | 776 | border: 1px solid var(--border); border-radius: var(--radius); | |
| 750 | 777 | background: var(--field-bg); | |
| 751 | 778 | display: flex; flex-direction: column; gap: 7px; | |
@@ -3573,10 +3600,10 @@ | |||
| 3573 | 3600 | if (m.type === 'config'){ | |
| 3574 | 3601 | // D7 — the escape hatch. 0 means "follow the default": clearing the property lets the stylesheet | |
| 3575 | 3602 | // value win again, rather than pinning it to whatever the default happened to be at the time. | |
| 3576 | - const rootLog = document.getElementById('log'); | ||
| 3577 | - if (rootLog){ | ||
| 3578 | - rootLog.style.setProperty('--prose-size', m.proseSize ? m.proseSize + 'px' : ''); | ||
| 3579 | - rootLog.style.setProperty('--prose-max', m.proseWidth ? m.proseWidth + 'px' : ''); | ||
| 3603 | + const shell = document.body; | ||
| 3604 | + if (shell){ | ||
| 3605 | + shell.style.setProperty('--prose-size', m.proseSize ? m.proseSize + 'px' : ''); | ||
| 3606 | + shell.style.setProperty('--prose-max', m.proseWidth ? m.proseWidth + 'px' : ''); | ||
| 3580 | 3607 | } | |
| 3581 | 3608 | const label = m.provider === 'claude' ? prettyModel(m.model) : m.model; | |
| 3582 | 3609 | const mEl = document.getElementById('model'); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments