ui: round 5 — AGENT'S THINKING buys the 3ch rail; the standard chord; dashed model names
- THE 3CH RAIL: 'AGENT’S THINKING' (16ch, flush) − 'YOUR THINKING' (13ch) = 3ch of mono — the rail widens to 3ch (border + padding), keeping the chevrons aligned while giving the quote room to breathe (the 1ch rail read cramped). YOU row follows. - THE STANDARD CHORD everywhere: Enter submits, Shift+Enter is a newline, ⌘/Ctrl+Enter works too — the teaching thinking field drops the ⌘-only Gmail convention; the hint reads '↵ submits · ⇧↵ newline' in both docks, shown in text mode too (it Enter-submits as well). - The transcript-end optimistic placeholder joins the register: small mono caps THINKING… (was text-sm sentence case). - Model names keep their dashes: prettyModel renders 'glm-5.3-flash' exactly as written (no auto-caps, no dash→space join).
This commit is contained in:
@@ -137,7 +137,7 @@ const defaultGetThinkingMessage = (isStreaming: boolean) => {
|
||||
if (isStreaming) {
|
||||
return <Shimmer duration={1}>Thinking...</Shimmer>;
|
||||
}
|
||||
return <p>AGENT THINKING</p>;
|
||||
return <p>AGENT’S THINKING</p>;
|
||||
};
|
||||
|
||||
export const ReasoningTrigger = memo(
|
||||
|
||||
+4
-4
@@ -1259,7 +1259,7 @@ export function Chat({
|
||||
User text renders plain — the model's LaTeX pipeline is not
|
||||
applied to learner-authored text ($ stays $, no surprises).
|
||||
Rendered WITHOUT the Message wrapper — that is the bubble. */
|
||||
<div data-testid="user-message" className="my-1 w-full border-l-2 border-muted-foreground/30 pl-[calc(1ch-2px)] font-ui text-xs">
|
||||
<div data-testid="user-message" className="my-1 w-full border-l-2 border-muted-foreground/30 pl-[calc(3ch-2px)] font-ui text-xs">
|
||||
{/* The rail GROUPS (owner round 4, 2026-10-05): the YOU heading
|
||||
sits INSIDE the rail, same mono-xs register and same 1ch
|
||||
rail as the thinking rows — one quote geometry. */}
|
||||
@@ -1365,10 +1365,10 @@ export function Chat({
|
||||
entered by external discovery (wake) / the poll
|
||||
fallback. Never collapsible itself. */}
|
||||
{(status === "submitted" || turnInFlight) && (
|
||||
<span className="flex items-center gap-2">
|
||||
<span className="flex items-center gap-2 font-ui text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||
<BrailleSpinner label="Thinking" />
|
||||
<Shimmer duration={1} className="text-sm">
|
||||
Thinking…
|
||||
<Shimmer duration={1}>
|
||||
THINKING…
|
||||
</Shimmer>
|
||||
</span>
|
||||
)}
|
||||
|
||||
@@ -820,9 +820,10 @@ function QuestionDockForm({
|
||||
onEscape();
|
||||
return;
|
||||
}
|
||||
// ⌘↵ on macOS, Ctrl↵ elsewhere — the Gmail convention; plain
|
||||
// Enter stays a newline (this field is for dumping).
|
||||
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
||||
// THE STANDARD CHORD (owner round 5, 2026-10-05): Enter
|
||||
// submits, Shift+Enter is a newline, ⌘/Ctrl+Enter works
|
||||
// too — identical to the practice dock and the composer.
|
||||
if (e.key === "Enter" && (!e.shiftKey || e.metaKey || e.ctrlKey)) {
|
||||
e.preventDefault();
|
||||
submit();
|
||||
}
|
||||
@@ -838,11 +839,9 @@ function QuestionDockForm({
|
||||
/>
|
||||
)}
|
||||
<div className="flex items-center justify-between gap-2 p-1">
|
||||
{qd.mode !== "text" && (
|
||||
<span aria-hidden className="pl-1.5 text-xs text-muted-foreground">
|
||||
⌘/Ctrl + ↵ submits
|
||||
</span>
|
||||
)}
|
||||
<span aria-hidden className="pl-1.5 text-xs text-muted-foreground">
|
||||
↵ submits · ⇧↵ newline
|
||||
</span>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={!canSubmit}
|
||||
|
||||
@@ -33,16 +33,18 @@ export function ThinkingBlock({
|
||||
return (
|
||||
/* 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
|
||||
rail's full width (border + padding) is exactly THREE CHARACTERS of
|
||||
the mono heading font — 'YOUR THINKING' is three chars shorter
|
||||
than 'AGENT'S THINKING', so with the user row offset by the rail
|
||||
and the agent row flush, the chevrons line up vertically. Three
|
||||
(not one, owner round 5): the wider gap reads better than the
|
||||
cramped single-char rail. The heading
|
||||
register is the card eyebrows' small mono caps (text-xs = the
|
||||
11px rung). */
|
||||
<div
|
||||
data-testid={testId}
|
||||
data-commit={dataCommit === undefined ? undefined : dataCommit ? "true" : "false"}
|
||||
className="lh-card-enter my-1 w-full border-l-2 border-muted-foreground/30 pl-[calc(1ch-2px)] font-ui text-xs"
|
||||
className="lh-card-enter my-1 w-full border-l-2 border-muted-foreground/30 pl-[calc(3ch-2px)] font-ui text-xs"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -146,7 +146,7 @@ describe("render smoke tests", () => {
|
||||
assert.match(html, /Why this answer\? What are you unsure about\?/, "placeholder invites, not apologizes");
|
||||
assert.ok(!html.includes("optional"), "the field is never called optional");
|
||||
assert.match(html, /Submit answer/, "send becomes Submit answer");
|
||||
assert.match(html, /⌘\/Ctrl \+ ↵ submits/, "the ⌘/Ctrl+Enter shortcut is discoverable");
|
||||
assert.match(html, /↵ submits · ⇧↵ newline/, "the standard chord is discoverable (owner round 5)");
|
||||
// The v1 desync bug: options are buttons with ARIA roles, not native inputs.
|
||||
assert.ok(!html.includes('type="radio"'), "no native radio inputs");
|
||||
assert.ok(html.includes('role="radio"'), "button-based radio role present");
|
||||
|
||||
Reference in New Issue
Block a user