From 9b75b4f785f04fba6c9e80382b8bebcf97747e32 Mon Sep 17 00:00:00 2001 From: amosblomqvist Date: Mon, 5 Oct 2026 04:39:47 +0300 Subject: [PATCH] =?UTF-8?q?ui:=20consistency=20sweep=20=E2=80=94=20the=201?= =?UTF-8?q?ch=20rail=20geometry,=20Submit=20thinking,=20no=20auto-caps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Owner round 4 (2026-10-05): - THE RAIL IS THE MISSING CHARACTER: rail + padding = exactly 1ch of the mono heading font. 'YOUR THINKING' (13ch) + rail == 'AGENT THINKING' (14ch) flush — the chevrons line up vertically, no fixed columns. The YOU heading joins the rail (label inside, like the thinking rows) — one quote geometry everywhere. - HEADING REGISTER: YOUR THINKING / AGENT THINKING / YOU all use the card eyebrows' small mono caps (text-xs = the 11px rung, font-medium uppercase tracking-wide) — the app chrome is JetBrains Mono. - SUBMIT THINKING: the practice button is now literally the question dock's Button (h-9, px-3.5) in one p-1 row with the hint left ('↵ submits · ⇧↵ newline') — the keyboard hints are back. Corner radii concentric in both docks: shell 16 − 6 = field 10 − 4 = button 6 (rounded-[10px] fields, rounded-[6px] buttons — the old rounded-xl/12 was the 'too large' culprit). - MODEL NAMES: prettyModel no longer auto-capitalizes — names render exactly as their providers write them ('glm 5.3 flash'). - Quiz explanations pulled closer (mt-3 → mt-2). --- components/answered-card.tsx | 4 ++-- components/chat.tsx | 11 ++++++----- components/practice-dock.tsx | 22 ++++++++++++++-------- components/question-dock.tsx | 4 ++-- components/thinking-block.tsx | 20 ++++++++++++-------- components/usage-format.ts | 4 +++- tests/render-settings.test.tsx | 2 +- tests/render-stats-bar.test.tsx | 12 ++++++------ 8 files changed, 46 insertions(+), 33 deletions(-) diff --git a/components/answered-card.tsx b/components/answered-card.tsx index 9a53f4f..5b900af 100644 --- a/components/answered-card.tsx +++ b/components/answered-card.tsx @@ -150,7 +150,7 @@ export function AnsweredCard({ answer }: { answer: QuestionAnswerData }) { verdict shows, but the explanation sits collapsed — viewable, never center stage. The teaching that follows resolves the prediction; THAT is the real explanation. */ -
+
+ Submit thinking +
diff --git a/components/question-dock.tsx b/components/question-dock.tsx index fcaae65..ecd9ea9 100644 --- a/components/question-dock.tsx +++ b/components/question-dock.tsx @@ -769,7 +769,7 @@ function QuestionDockForm({ >
{qd.mode === "text" ? "Your answer" : "YOUR THINKING"} @@ -846,7 +846,7 @@ function QuestionDockForm({ diff --git a/components/thinking-block.tsx b/components/thinking-block.tsx index 2bb1748..5adbbaa 100644 --- a/components/thinking-block.tsx +++ b/components/thinking-block.tsx @@ -31,27 +31,31 @@ export function ThinkingBlock({ }) { const [open, setOpen] = useState(false); // arrives collapsed, always return ( - /* The rail GROUPS (owner correction, 2026-10-05): the label sits - INSIDE the rail — the block reads as one quote, ownership clear - from the rail alone, collapsed or expanded. Same shape as the - user text ("You") row. */ + /* The rail GROUPS and the rail IS THE MISSING CHARACTER (owner + rounds, 2026-10-05): the heading sits INSIDE the rail, and the + rail's full width (border + padding) is exactly ONE CHARACTER of + the mono heading font — 'YOUR THINKING' is one char shorter than + 'AGENT THINKING', so with the user row offset by the rail and the + agent row flush, the chevrons line up vertically. The heading + register is the card eyebrows' small mono caps (text-xs = the + 11px rung). */
{open && ( - {text} + {text} )}
); diff --git a/components/usage-format.ts b/components/usage-format.ts index 0e5c259..b19a859 100644 --- a/components/usage-format.ts +++ b/components/usage-format.ts @@ -39,6 +39,8 @@ export function prettyModel(id: string, qualified = false): string { const short = bare.includes("/") ? bare.slice(bare.lastIndexOf("/") + 1) : bare; const parts = short.split("-"); const trimmed = /^\d+$/.test(parts[parts.length - 1] ?? "") ? parts.slice(0, -1) : parts; - const pretty = trimmed.map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" "); + // No auto-capitalization (owner round 4, 2026-10-05): model names + // render exactly as their providers write them. + const pretty = trimmed.join(" "); return qualified && provider ? `${pretty} · ${provider}` : pretty; } \ No newline at end of file diff --git a/tests/render-settings.test.tsx b/tests/render-settings.test.tsx index d5e2ee1..9bf2a56 100644 --- a/tests/render-settings.test.tsx +++ b/tests/render-settings.test.tsx @@ -155,7 +155,7 @@ describe("AgentSection (thin SSR)", () => { ); // The trigger shows the stored id even with no catalog loaded (a // trigger reading "Default" over a live override would lie). - assert.ok(html.includes("Glm 4.7 Flash"), "the override id is visible (prettyModel form)"); + assert.ok(html.includes("glm 4.7 flash"), "the override id is visible (prettyModel form, no auto-caps)"); assert.ok(tagOf(html, "toggle-tool-demo").includes('aria-checked="false"'), "demo off"); assert.ok(tagOf(html, "toggle-tool-visual").includes('aria-checked="true"'), "visual still on"); }); diff --git a/tests/render-stats-bar.test.tsx b/tests/render-stats-bar.test.tsx index 289483e..e67c0f5 100644 --- a/tests/render-stats-bar.test.tsx +++ b/tests/render-stats-bar.test.tsx @@ -77,20 +77,20 @@ describe("stats bar", () => { assert.match(html, /data-testid="stats-context">11k { - assert.equal(prettyModel("z-ai/glm-5.3-flash"), "Glm 5.3 Flash"); - assert.equal(prettyModel("qwen/qwen3.8-max-0902"), "Qwen3.8 Max"); + it("prettyModel strips vendor + date suffix (no auto-caps)", () => { + assert.equal(prettyModel("z-ai/glm-5.3-flash"), "glm 5.3 flash"); // no auto-caps (owner round 4) + assert.equal(prettyModel("qwen/qwen3.8-max-0902"), "qwen3.8 max"); }); it("provider-qualified stamps (usage contract, model-slots wave)", () => { // qualified: the provider rides as a quiet suffix — federation makes // the same model via two providers different bookkeeping - assert.equal(prettyModel("openrouter:z-ai/glm-5.3-flash", true), "Glm 5.3 Flash · openrouter"); + assert.equal(prettyModel("openrouter:z-ai/glm-5.3-flash", true), "glm 5.3 flash · openrouter"); assert.equal(prettyModel("openai:gpt-5.2", true), "Gpt 5.2 · openai"); // unqualified on a qualified stamp: provider silently dropped (old shape) - assert.equal(prettyModel("openrouter:z-ai/glm-5.3-flash"), "Glm 5.3 Flash"); + assert.equal(prettyModel("openrouter:z-ai/glm-5.3-flash"), "glm 5.3 flash"); // qualified on a bare id: no suffix invented - assert.equal(prettyModel("z-ai/glm-5.3-flash", true), "Glm 5.3 Flash"); + assert.equal(prettyModel("z-ai/glm-5.3-flash", true), "glm 5.3 flash"); }); });