New-session page reads like a pre-session: no phase chip, outlined bar, opening-question placeholder
Three owner fixes for /chat/new (refinement round 4, 2026-09-24) —
the page must stop looking like a session that's already running:
1. NO PHASE CHIP: the header's <PhaseChip phase="probe" /> dies —
no session has started, so no phase exists yet. Active sessions
keep their chip (chat.tsx's derives from the live timeline).
2. TOP BAR STRUCTURE MATCHS SESSIONS: the header gains the same
border-b border-border as the chat header (h-15, lh-drag,
60px). The floating-bar look is gone; /chat/new now reads as
the same shell with empty content.
3. COMPOSER PLACEHOLDER = THE OPENING QUESTION: active sessions
keep "Ask, answer, or steer the lesson…" (now the DEFAULT of a
new Composer `placeholder` prop), but the fresh page asks what
the graph view's new-session input asks — "What do you want to
learn?" No lesson is in flight, so the composer must not read
like one is.
The ConversationEmptyState intro card ("The teacher will open by
probing…") stays, per owner confirmation.
Live-verified on :3001 /chat/new: no phase-chip node, computed
1px header border rgb(67,67,67) at h-15/60px, placeholder reads
"What do you want to learn?"; the empty-state card intact. Unit
test pins the default session placeholder AND the override.
903/903.
This commit is contained in:
@@ -13,7 +13,7 @@ import { describe, it } from "node:test";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import { Composer, enterAction } from "../components/composer.tsx";
|
||||
|
||||
function render(opts: { busy?: boolean; canSend?: boolean } = {}) {
|
||||
function render(opts: { busy?: boolean; canSend?: boolean; placeholder?: string } = {}) {
|
||||
return renderToStaticMarkup(
|
||||
<Composer
|
||||
busy={opts.busy ?? false}
|
||||
@@ -22,6 +22,7 @@ function render(opts: { busy?: boolean; canSend?: boolean } = {}) {
|
||||
onSend={() => {}}
|
||||
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");
|
||||
|
||||
Reference in New Issue
Block a user