diff --git a/components/composer.tsx b/components/composer.tsx index 4e81e6b..6034d7c 100644 --- a/components/composer.tsx +++ b/components/composer.tsx @@ -35,6 +35,7 @@ export function Composer({ autoFocus, verdict, onEscape, + placeholder = "Ask, answer, or steer the lesson…", }: { busy: boolean; value: string; @@ -50,6 +51,10 @@ export function Composer({ /** Escape while a dictation runs stops it (STT wave, 2026-09-17). No-op * when absent — Esc otherwise means nothing in the composer. */ onEscape?: () => void; + /** The textarea's placeholder (owner refinement round, 2026-09-24): + * active sessions read "Ask, answer, or steer the lesson…"; the fresh + * new-session page asks the graph view's opening question instead. */ + placeholder?: string; }) { return (
{/* h-15 (60px) matches the chat header and the sidebar's LH wordmark band (owner, round 6). */} -
+
New session
-
@@ -125,6 +123,11 @@ export function DraftShell({ canSend={canSend} autoFocus onEscape={dictation.active ? dictation.cancel : undefined} + // The opening question, same as the graph view's new-session + // input (owner refinement round, 2026-09-24) — no lesson has + // started yet, so the composer must not read like one is in + // flight. + placeholder="What do you want to learn?" />
{}} onStop={() => {}} canSend={opts.canSend ?? true} + {...(opts.placeholder ? { placeholder: opts.placeholder } : {})} />, ); } @@ -29,10 +30,16 @@ function render(opts: { busy?: boolean; canSend?: boolean } = {}) { describe("Composer", () => { it("chat placeholder + send button", () => { const html = render(); - assert.match(html, /Ask, answer, or steer the lesson/); + assert.match(html, /Ask, answer, or steer the lesson/, "the default — active sessions"); assert.ok(html.includes('aria-label="Send"'), "send button present"); }); + it("placeholder is overridable — the new-session page asks the graph view's question", () => { + const html = render({ placeholder: "What do you want to learn?" }); + assert.match(html, /What do you want to learn\?/); + assert.ok(!html.includes("Ask, answer"), "the session placeholder must not ride along"); + }); + it("busy: send button becomes stop", () => { const html = render({ busy: true }); assert.ok(html.includes('aria-label="Stop"'), "stop replaces send while streaming");