Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 6 additions & 13 deletions extensions/levelcode-ai/media/chat.html
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@
/* font-size is sized off the CONTAINER width (cqi) — reliable in a webview where vw = the whole
editor, not this panel — so the wordmark always fits and the last glyph is never clipped.
line-height:1 makes the box-drawing rows connect into solid letters. */
#empty .lc-ascii { font-family: var(--vscode-editor-font-family, ui-monospace, monospace); font-size: clamp(5px, 3.6cqi, 13px); line-height: 1; white-space: pre; color: var(--vscode-terminal-ansiGreen, #98c379); opacity: 1; width: max-content; max-width: 100%; margin: 2px auto 6px; overflow-x: auto; user-select: none; }
#empty .lc-ascii { font-family: var(--vscode-editor-font-family, ui-monospace, monospace); font-size: clamp(5px, 4.6cqi, 13px); line-height: 1; white-space: pre; color: var(--vscode-terminal-ansiGreen, #98c379); opacity: 1; width: max-content; max-width: 100%; margin: 2px auto 6px; overflow-x: auto; user-select: none; }
#empty .lc-ascii-sub { font-family: var(--vscode-editor-font-family, monospace); font-size: 11px; letter-spacing: .22em; color: var(--muted); opacity: .9; margin-bottom: 14px; }
#empty .starters { display: flex; flex-wrap: wrap; gap: 7px; justify-content: center; margin-top: 14px; }
#empty .starter { cursor: pointer; border: 1px solid var(--border); border-radius: 14px; padding: 4px 11px; font-size: 11.5px; background: var(--field-bg); color: var(--vscode-foreground); opacity: .95; }
Expand Down Expand Up @@ -1259,18 +1259,11 @@
<body>
<div id="log">
<div id="empty">
<div class="lc-ascii-wrap"><pre class="lc-ascii" role="img" aria-label="LevelCode AI">██╗ ███████╗██╗ ██╗███████╗██╗
██║ ██╔════╝██║ ██║██╔════╝██║
██║ █████╗ ██║ ██║█████╗ ██║
██║ ██╔══╝ ╚██╗ ██╔╝██╔══╝ ██║
███████╗███████╗ ╚████╔╝ ███████╗███████╗
╚══════╝╚══════╝ ╚═══╝ ╚══════╝╚══════╝
██████╗ ██████╗ ██████╗ ███████╗
██╔════╝██╔═══██╗██╔══██╗██╔════╝
██║ ██║ ██║██║ ██║█████╗
██║ ██║ ██║██║ ██║██╔══╝
╚██████╗╚██████╔╝██████╔╝███████╗
╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝</pre></div>
<div class="lc-ascii-wrap"><pre class="lc-ascii" role="img" aria-label="LevelCode AI">╭──────────────────────────────╮
│ │
│ ▁▃▅█ L E V E L C O D E │
│ │
╰──────────────────────────────╯</pre></div>
<div class="lc-ascii-sub">levelcode.ai</div>
<div class="empty-copy">Ask about your code, or describe what to build. The open file is sent as context; add a selection with <b>+</b> or ⌥⌘A.</div>
<div class="starters">
Expand Down
53 changes: 40 additions & 13 deletions extensions/levelcode-ai/test/webviewCss.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -578,25 +578,52 @@ test('TRANSCRIPT: the user bubble hugs its content, and is capped short of the c
'tint is the secondary cue and still earns its place — side alone would drop on a wrapped log');
});

test('WORDMARK: the empty-state logo fits its container and has an accessible name', () => {
// NOT asserted here: which characters it is drawn from. A previous version of this test required
// full blocks only, on the theory that `█` tiles seamlessly while `▀`/`▄` can seam. Half of that is
// right — `▀` above `▄` does leave a gap — but the other half is not: whether `█` FILLS its cell is
// a property of the FONT, not of the character. In Monaco it does not, and a wordmark built on that
test('WORDMARK: the mark and its cqi scale factor stay in agreement', () => {
// NOT asserted here: which characters it is drawn from. A previous version required full blocks
// only, on the theory that `█` tiles seamlessly while `▀`/`▄` can seam. Half of that is right —
// `▀` above `▄` does leave a gap — but the other half is not: whether `█` FILLS its cell is a
// property of the FONT, not of the character. In Monaco it does not, and a wordmark built on that
// assumption shattered into disconnected bars in the editor while looking perfect in a harness
// running SF Mono. The lesson is that this file cannot check the thing that actually matters, so it
// should stop pretending to; ASCII art has to be looked at in the target font.
// running SF Mono.
//
// The current mark sidesteps that entirely: box-drawing rules are CONNECTOR glyphs that join in
// every monospace family, and the letters are real text rather than pixel art. Verified by
// rendering it in Monaco, SF Mono, Menlo, Courier New, Andale Mono, Consolas and the generic
// fallback — legible in all seven. That check cannot live in this file; ASCII art has to be looked
// at in the target font.
const m = /<pre class="lc-ascii"[^>]*>([\s\S]*?)<\/pre>/.exec(html);
assert.ok(m, 'the empty-state wordmark is gone');
const art = m[1].replace(/^\n/, '');

// This bound IS checkable and is not about glyphs: the logo is sized from the container
// (clamp(5px, 3.6cqi, 13px)) inside #empty, which is capped at 560px. Past ~44 columns it stops
// fitting and the pre grows a horizontal scrollbar under the logo.
const lines = art.split('\n');
const cols = Math.max(...lines.map((l) => l.length));
assert.ok(cols <= 44, 'the wordmark is ' + cols + ' columns; wider than ~44 overflows #empty (max 560px)');
assert.ok(lines.length <= 14, 'the wordmark is ' + lines.length + ' lines; it has to leave room for the prompt beneath it');

// What IS checkable, and the thing most likely to be got wrong: the mark is sized from the
// container, so its WIDTH IN COLUMNS and the cqi factor are two halves of one number. Widen the art
// without lowering the factor and it overflows; narrow it without raising the factor and it shrinks
// to a stamp floating in white space. The 41-column mark used 3.6cqi; this 32-column one uses 4.6
// precisely to land in the same place.
// The selector is anchored with a negative lookahead because `.lc-ascii-wrap` is declared BEFORE
// `.lc-ascii` and `.lc-ascii-sub` right after it. A looser `\.lc-ascii[^{]*\{` reads the right rule
// today only because -wrap happens to declare no font-size — luck of content, not construction, and
// it would silently start measuring the wrong rule the day one of them gains a cqi clamp.
const rule = /\.lc-ascii(?![-\w])[^{]*\{([^}]*)\}/.exec(css);
assert.ok(rule, 'the .lc-ascii rule is gone');
const cqi = /font-size:\s*clamp\(\s*\d+px\s*,\s*([\d.]+)cqi/.exec(rule[1]);
assert.ok(cqi, 'the wordmark is no longer sized from its container');

// Asserted on cols x cqi directly, which IS the contract: the art width in columns and the font
// size as a percentage of the container are two halves of one number, and their product is what
// stays constant. The previous version multiplied in a hard-coded 0.6em cell width to report a
// tidy "fill %", but that factor is a property of whatever font the editor resolves — it differs
// between Monaco and SF Mono — so it dressed the real invariant in a precision it does not have.
const product = cols * Number(cqi[1]);
assert.ok(product > 132 && product < 162,
'cols x cqi is ' + product.toFixed(1) + ' (' + cols + ' columns at ' + cqi[1] + 'cqi). '
+ 'It must stay near 147 — the value both shipped marks share (41x3.6, 32x4.6). Lower and the '
+ 'mark shrinks to a stamp in white space; higher and it touches the edges and can overflow.');

assert.ok(lines.length <= 14,
'the wordmark is ' + lines.length + ' lines; it has to leave room for the prompt and starters beneath it');

// The accessible name is the whole reason a picture made of text is not a wall of noise to a
// screen reader.
Expand Down