practice UI: the dock, the transcript cards, layered-Esc discard

- PracticeDock (components/practice-dock.tsx): the active problem
  replaces the composer — statement (markdown+LaTeX) above, the 'Your
  thinking' composer-twin below with the two submit lanes (Nudge =
  thinking without a commit; Commit = answer commit; ⌘/Ctrl+Enter
  commits). Dictation claims the thinking field.
- Transcript cards (practice-cards.tsx + the artifact registry): the
  problem card (compact-expandable statement — the commitment NEVER
  renders), the conclude card (outcome + verdict + reveal; the
  dismissal synthesis is one muted line), and the user-side thinking
  register cards (Your thinking / Your solution).
- view.ts: the problem pose joins the placeholder fork (the ack never
  flips the part); practice-thinking markers project as data parts;
  problem-dismissed markers project nothing.
- chat.tsx: activeProblemOf drives the dock branch (question > problem
  > composer), the esc layering gains the problem rung (below question,
  above turn) with its discard confirm + the silent marker route; the
  thinking submissions POST through the session's optimistic appends.
This commit is contained in:
amosblomqvist
2026-10-04 21:55:54 +03:00
parent 4bea0b46df
commit 59bf5bf219
10 changed files with 650 additions and 19 deletions
+6 -1
View File
@@ -24,7 +24,7 @@ import { createPortal } from "react-dom";
*/
/** What Esc is aborting — drives copy and the confirm action. */
export type AbortMode = "turn" | "question";
export type AbortMode = "turn" | "question" | "problem";
const COPY: Record<AbortMode, { title: string; line: string; action: string }> = {
turn: {
@@ -37,6 +37,11 @@ const COPY: Record<AbortMode, { title: string; line: string; action: string }> =
line: "Skipped — the teacher moves on without it.",
action: "Dismiss",
},
problem: {
title: "Discard this problem?",
line: "The problem is dropped — no solution is revealed.",
action: "Discard",
},
};
/** The dialog's pure body — exported for SSR pins (the delete-node