Skip to content

Commit 8a6f1b1

Browse files
committed
fix(chat): the context and review bars sat flush left, not in the column
Reported from the editor tab: the context-window card and the Keep all / Undo all bar hug the left window edge while the transcript and composer are centred. The shell-column rule centres seven bars: #bgTasksBar, #ctxBar, #planBar, #reviewBar, #workbar, #composer, #status { width: calc(100% - 2 * var(--shell-x)); max-width: var(--prose-max); margin-inline: auto; <- this } Every selector in it is a BARE ID, so a later bare-id rule ties on specificity and wins on order. Three of the seven then declare a `margin:` SHORTHAND hundreds of lines down — `margin: 0 8px 6px` on #ctxBar and #bgTasksBar, `margin: 0 8px 8px` on #reviewBar — and a shorthand writes every longhand it covers, so margin-inline: auto silently became 8px. The bars kept the right WIDTH (the width calc is unopposed) and lost their position, which is exactly what the report shows: correct size, wrong place. Those insets were left over from the sidebar era and are redundant now — the width calc already insets by --shell-x. Changed to margin-block, which cannot touch the inline axis. #bgTasksBar had the same bug and was not in the report; it only shows while a background command is running. #composer also declares a shorthand, `margin: 8px auto` — its inline slot IS auto, so it re-states the centring rather than breaking it. Left alone. Writing the guard I first banned every `margin:` shorthand and it flagged the composer, which would have been a false positive; the rule is "inline slot must be auto", not "no shorthand". The guard walks the shell rule's OWN selector list rather than three hard-coded ids, so a bar added to the column later is covered the day it is added. It parses the shorthand's slots ([all] / [block inline] / [top inline bottom] / [top right bottom left]) and fails only when the inline slot is not auto. Bypass-verified, each by reverting the fix: - the reported bug verbatim (3-slot shorthand on #ctxBar) - the same on #reviewBar and #bgTasksBar - a 4-slot shorthand with asymmetric right/left - margin-left and margin-inline set directly - the shell column dropping margin-inline entirely - control: `margin: 6px auto` still passes, so the guard is not blanket Verified by rendering the real bars at 1100px against develop and against the fix. 34 suites green.
1 parent 64c7073 commit 8a6f1b1

2 files changed

Lines changed: 49 additions & 3 deletions

File tree

extensions/levelcode-ai/media/chat.html

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@
5858
max-width: var(--prose-max);
5959
margin-inline: auto;
6060
}
61+
/* Every element above is a bare id, so a LATER bare-id rule ties on specificity and wins. A
62+
`margin:` shorthand in one of those rules silently resets margin-inline to whatever its
63+
left/right slot says — which is how #ctxBar, #reviewBar and #bgTasksBar ended up flush against
64+
the window edge while the composer centred. Their own inset is redundant anyway: the width
65+
calc above already insets by --shell-x. Set margin-block in these rules, never margin.
66+
test/webviewCss.test.js pins this for the whole list. */
6167

6268
/* ---- conversation log ---- */
6369
/* The measure, the type and the inset are all declared on `body` (see above) so the composer and the
@@ -628,7 +634,7 @@
628634
/* Sits between the message log and the composer — sticky review summary for applied edits. */
629635
#reviewBar {
630636
display: flex; align-items: center; gap: 8px; flex: 0 0 auto;
631-
margin: 0 8px 8px; padding: 7px 11px; font-size: 12px;
637+
margin-block: 0 8px; padding: 7px 11px; font-size: 12px;
632638
background: var(--vscode-editorWidget-background, #21252b);
633639
border: 1px solid var(--border); border-radius: 8px;
634640
}
@@ -665,7 +671,7 @@
665671

666672
/* ---- agent plan checklist ---- */
667673
/* context-window usage meter (appears >50%, warns >80%, critical >92%) */
668-
#ctxBar { flex: 0 0 auto; margin: 0 8px 6px; padding: 7px 11px; border-radius: 8px; border: 1px solid var(--border); background: var(--vscode-editorWidget-background, rgba(127,127,127,.08)); font-size: 11px; }
674+
#ctxBar { flex: 0 0 auto; margin-block: 0 6px; padding: 7px 11px; border-radius: 8px; border: 1px solid var(--border); background: var(--vscode-editorWidget-background, rgba(127,127,127,.08)); font-size: 11px; }
669675
#ctxBar .ctxrow { display: flex; justify-content: space-between; align-items: center; color: var(--muted); margin-bottom: 5px; }
670676
#ctxBar .ctxnum { font-variant-numeric: tabular-nums; }
671677
#ctxBar .ctxtrack { height: 5px; border-radius: 3px; background: rgba(127,127,127,.22); overflow: hidden; }
@@ -679,7 +685,7 @@
679685
#ctxBar .ctxnew:hover { background: var(--vscode-button-hoverBackground); }
680686
/* sticky active-plan bar (sits just above the review bar) — opaque so the log can't show behind it */
681687
/* Background tasks tray — collapsed by default; lists commands started with background:true */
682-
#bgTasksBar { flex: 0 0 auto; margin: 0 8px 6px; border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
688+
#bgTasksBar { flex: 0 0 auto; margin-block: 0 6px; border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
683689
background: var(--vscode-editorWidget-background, rgba(127,127,127,.08)); font-size: 12px; }
684690
.bgt-head { display: flex; align-items: center; gap: 7px; padding: 8px 11px; cursor: pointer; user-select: none; color: var(--vscode-foreground); }
685691
.bgt-head:hover { background: var(--vscode-toolbar-hoverBackground, rgba(127,127,127,.12)); }

extensions/levelcode-ai/test/webviewCss.test.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,4 +729,44 @@ test('SESSION CARD: every action button keeps a label for pointers and screen re
729729
assert.match(pure, /aria-label="' \+ label \+ '"/, 'no accessible name on an icon-only button');
730730
});
731731

732+
test('SHELL COLUMN: no member re-declares an inline margin, which would un-centre it', () => {
733+
// The shell rule centres seven bars with `margin-inline: auto`, and every selector in it is a
734+
// BARE ID. So a later bare-id rule ties on specificity and wins — and a `margin:` SHORTHAND in
735+
// one of those rules silently resets margin-inline to its left/right slot. That is exactly how
736+
// #ctxBar, #reviewBar and #bgTasksBar shipped flush against the window edge while the composer
737+
// centred: `margin: 0 8px 6px` beat `margin-inline: auto` by sitting 600 lines further down.
738+
//
739+
// This walks the rule's OWN selector list rather than three hard-coded ids, so a bar added to
740+
// the shell column later is covered the day it is added.
741+
const shell = /\n\s*(#[\w#, -]*?#composer[\w#, -]*?)\s*\{([^}]*)\}/.exec(cssBlocks);
742+
assert.ok(shell, 'the shell-column rule is gone');
743+
assert.match(shell[2], /margin-inline:\s*auto/, 'the shell column no longer centres anything');
744+
745+
const ids = shell[1].split(',').map((x) => x.trim()).filter((x) => /^#[\w-]+$/.test(x));
746+
assert.ok(ids.length >= 6, 'expected the whole bar list, got: ' + ids.join(' '));
747+
748+
for (const id of ids) {
749+
const re = new RegExp('\\n\\s*' + id + '\\s*\\{([^}]*)\\}', 'g');
750+
let hit;
751+
while ((hit = re.exec(cssBlocks))) {
752+
const body = hit[1];
753+
// A shorthand is only a problem when its INLINE slot is not auto. `margin: 8px auto`
754+
// re-states the centring and is fine; `margin: 0 8px 6px` destroys it. Slots are
755+
// [all] / [block inline] / [top inline bottom] / [top right bottom left].
756+
const sh = /(?:^|;)\s*margin\s*:\s*([^;}]+)/.exec(body);
757+
if (sh) {
758+
const p = sh[1].trim().split(/\s+/);
759+
const inline = p.length === 1 ? [p[0]] : p.length === 4 ? [p[1], p[3]] : [p[1]];
760+
assert.ok(inline.every((v) => v === 'auto'),
761+
id + ' has `margin: ' + sh[1].trim() + '` — its inline slot is not auto, so it '
762+
+ 'resets margin-inline and pins the bar to one edge. Use margin-block; the width '
763+
+ 'calc already insets by --shell-x.');
764+
}
765+
const direct = /margin-(?:left|right|inline(?:-start|-end)?)\s*:\s*([^;}]+)/.exec(body);
766+
assert.ok(!direct || direct[1].trim() === 'auto',
767+
id + ' sets an inline margin directly, which beats the shell column\'s auto');
768+
}
769+
}
770+
});
771+
732772
console.log('webviewCss: ' + n + ' tests passed');

0 commit comments

Comments
 (0)