FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Merge pull request #75 from levelcodeai/feat/chat-shell-column · levelcodeai/levelcode@b7b4472 · GitHub

Commit b7b4472

Browse files
authored
Merge pull request #75 from levelcodeai/feat/chat-shell-column
feat(chat): one column for the whole panel, widened to the reference — T7
2 parents e65286f + ffa5f0b commit b7b4472

3 files changed

Lines changed: 221 additions & 38 deletions

File tree

‎docs/CHAT-TYPOGRAPHY.md‎

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,16 @@ Two observations worth stating plainly, because they explain almost everything:
4545

4646
### D1 — Constrain the measure. This is the single biggest lever.
4747

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.)*
5051

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:
5458

5559
| measured in the shipped font at 13px | |
5660
| --- | --- |
@@ -62,9 +66,21 @@ characters would be a 422px column, narrower than the sidebar. The print-typogra
6266
characters does not transfer to a technical chat: it assumes prose without identifiers, file paths or
6367
code, and a 422px column would wrap every code block constantly.
6468

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.
6884

6985
The elegant part: **in the sidebar this is a no-op.** The container is already narrower than the cap,
7086
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`:
196212
Tint stays as the secondary cue rather than being removed: side alone would fail on any surface that
197213
reflows the log to a single column.
198214

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+
199249
---
200250

201251
## 3. Slices
@@ -226,6 +276,11 @@ left and full-measure. **Exit:** a short turn renders as a short right-flush bub
226276
below the column, the assistant is untouched, and the prose inside the bubble is still left-aligned —
227277
all four measured, not eyeballed.
228278

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+
229284
**T5 — the escape hatch** *(S)*. D7. **Folded into T2 and shipped with it.** Sequencing it last was a
230285
mistake: T2 is the one slice that changes what every existing user sees, and shipping a divisive
231286
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
234289
Sequencing: T1 first and alone — it may turn out to be most of the perceived fix, and shipping it
235290
by itself is the cheapest way to find out before spending effort on T2–T4.
236291

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.
241298

242299
---
243300

‎extensions/levelcode-ai/media/chat.html‎

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@
2222
color: var(--vscode-foreground);
2323
background: transparent;
2424
display: flex; flex-direction: column; height: 100vh;
25-
}
2625

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;
3235
/* T2 (D2) — the READING type. `--vscode-font-size` is the size of menu labels and tree rows: right
3336
for chrome, wrong for three paragraphs of explanation. Message bodies alone get their own size
3437
and leading; every control around them keeps inheriting the workbench, so the panel still
@@ -39,7 +42,28 @@
3942
the wrong way. At the default 13px this still resolves to 14px, so nothing moves for anyone who
4043
has not changed it. */
4144
--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; }
4367
/* Log is a flex column → children default to flex-shrink:1. Any child with overflow:hidden (e.g. the
4468
approval/edit cards) then gets an auto min-size of 0 and the flex algorithm crushes it to an invisible
4569
line once the log overflows. Pin every child to its natural height; the log itself scrolls instead. */
@@ -48,12 +72,15 @@
4872
in this file are all cards, dialogs and the empty state. In a 380px sidebar the container bounded
4973
it, so it never looked wrong — but the chat can now open as an editor tab (AI: Open Chat in
5074
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.
5582
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
5784
sidebar is untouched. */
5885
#log > * { width: 100%; max-width: var(--prose-max); margin-inline: auto; box-sizing: border-box; }
5986
/* ---- per-response copy button (hover-reveal under a completed assistant message) ---- */
@@ -174,7 +201,7 @@
174201
opens the editor tab sees nothing move. `min-width` here is the WEBVIEW's own width — the iframe
175202
is sized to the panel, which is why the existing #empty/dialog rules already use vw/vh. */
176203
@media (min-width: 760px) {
177-
#log { padding: 20px 24px; gap: 1.15em; }
204+
#log { padding: 20px var(--shell-x); gap: 1.15em; }
178205
.msg .body p { margin-bottom: 1em; }
179206
.msg .body ul, .msg .body ol { margin-bottom: 1em; }
180207
/* More space ABOVE a heading than below it, so it binds to the section it introduces rather than
@@ -745,7 +772,7 @@
745772

746773
/* ---- composer ---- */
747774
#composer {
748-
margin: 8px; padding: 8px 8px 6px;
775+
margin: 8px auto; padding: 8px 8px 6px;
749776
border: 1px solid var(--border); border-radius: var(--radius);
750777
background: var(--field-bg);
751778
display: flex; flex-direction: column; gap: 7px;
@@ -3573,10 +3600,10 @@
35733600
if (m.type === 'config'){
35743601
// D7 — the escape hatch. 0 means "follow the default": clearing the property lets the stylesheet
35753602
// 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' : '');
35803607
}
35813608
const label = m.provider === 'claude' ? prettyModel(m.model) : m.model;
35823609
const mEl = document.getElementById('model');

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL