Commit Graph
5 Commits
Author SHA1 Message Date
amosblomqvist d653ba0e91 math: render escaped dollars inside inline math
micromark-extension-math's inline closer is code-span logic — any
size-matched $ run closes, backslash-escaped dollars included — so
"$x = \$5$" closed at the escape, errored in KaTeX, and could cascade
into later text. KaTeX itself renders the escaped dollar fine, and its
own auto-render scanner skips escaped dollars, so the author's intent
is unambiguous.

Fix at the render seam (transformMathDelimiters): inside a balanced
inline span, an escaped dollar becomes the dollar-free
\text{\textdollar} before tokenization, with an escape-aware closer
(odd-backslash dollars never close; even-backslash row-break closers
keep closing). Display spans are untouched (a lone $ can't close $$ —
the escape already survives there), prose escaped dollars, code, and
unbalanced spans pass through, and spans without escaped dollars emit
byte-identical text — corpus-verified over 489 dollar-bearing fields
in 40 real sessions (35 changed, all escaped-dollar spans; the
economics session's dollar-amount math now renders).

The latex-testing session's Test-6 question renders 14 KaTeX spans
with zero errors (was 12 + 2 errors). 1578/1578 tests both configs;
typecheck, lint, build, and Electron-runtime smoke green.
2026-10-13 06:36:05 +03:00
amosblomqvist bf29a2070f math: dollar delimiters end-to-end (exact answers, escaping examples, context rendering)
- switch the math authoring/rendering contract from \(...\)/\[...\] to the
  standard $...$ inline / $$...$$ display: prompts (20-question-tools,
  40-formatting), singleDollarTextMath on the renderer, legacy reader kept,
  and escape-debris recovery extended to dollar spans (mirroring micromark
  delimiter-run rules)
- exact answer membership now precedes debris cleanup in
  coerceCorrectAnswer (calculus incident: an exact sentence-final-period
  label was stripped as model debris, then rejected); option keys are
  passed at the boundary/grading seams, the dock no longer pre-coerces
- a complete, phase-correct JSON-escaping example rides the probe/quiz
  tool descriptions (serialized from one canonical body; quiz leads with
  type+nodeId), plus the one-sentence JSON-escaping rule in 40-formatting
- ask option descriptions render markdown/LaTeX in the pending dock;
  settled cards keep the details line and option descriptions
  retroactively, read from the persisted call arguments (chat passes
  part.input to AnsweredCard)

1566/1566 tests on both navigator configs; typecheck, lint, production
build, standalone packaging, and Electron-runtime smoke all green.
2026-10-13 06:24:33 +03:00
amosblomqvist f7a04f6c02 Default bold ink #c96b4a -> #ee928c
Owner default change (2026-09-23): the factory strong-color token
moves to the softer coral. The factory lives in the stylesheet
token (both theme blocks in globals.css) - settings' boldColor:null
means "factory" by design, so no record/schema change. The settings
row hint + placeholder follow, plus the placeholder test and two
comments that cited the old literal.

Live-verified: unset boldColor renders rgb(238,146,140) (#ee928c) on
the real <strong>; dialog hint reads "Empty = #ee928c".
2026-09-23 22:05:58 +03:00
amosblomqvist fb72b4fee3 Bold renders the real element: the Bold color setting applies
The owner's repro: the appearance Bold color never applied anywhere.
Root cause: streamdown's default `strong` component renders bold as
<span class="font-semibold" data-streamdown="strong"> - NOT a
<strong> element - while the app's ink plumbing (.lh-prose
:where(strong, b) in globals.css, zero specificity by design) matches
strong/b ELEMENTS. So bold text never took --lh-ink-strong: not the
factory #c96b4a, not any settings boldColor (it rendered plain
foreground at weight 600). Italic always worked because streamdown
leaves `em` native - hence the asymmetry the owner noticed.

Fix: a `strong` override in mdComponents (the stable module-level set,
so Streamdown's memoized tree keeps identity) renders the semantic
element: <strong data-streamdown="strong">. Screen readers announce
emphasis again, the designed token rule applies unmodified, and the
weight reads 700 (the .lh-prose rule) instead of the span's 600.

Both Streamdown surfaces (MessageResponse, reasoning) pass
mdComponents, so every markdown surface is covered.

Verified live: bold in seedplan now renders #c96b4a at weight 700 in a
real <strong>; after PUTting boldColor #7dd3fc the live strong flips
to rgb(125,211,252) with no reload; italic unchanged (#6fa9d6 native
em). Scratch record restored to unset.
2026-09-23 21:55:51 +03:00
Amos ef488224bc W3: presentation fixes — delimiters, line breaks, mermaid
- src/core/math-delims.ts: pure preprocessing for the \(...\)/\[...\] math
  contract — balanced delimiters rewrite to the two-dollar forms remark-math
  parses ($ is never math). Skips code fences/spans, escaped delimiters, and
  leaves unbalanced (mid-stream) delimiters untouched. Display math renders
  as a block: mid-paragraph gets blank-line padding; indented (list items)
  degrades to inline so list continuations don't half-parse.
- message.tsx: transform in the render path (children-memoized); math plugin
  now singleDollarTextMath: false — the currency hazard dies structurally.
  remark-breaks via the cjk remarkPluginsAfter slot (the bare remarkPlugins
  prop would replace the [remark-gfm, codeMeta] defaults).
- mermaid: dark theme + sans font via Streamdown's mermaid prop; dark-styled
  error fallback (components/mermaid-error.tsx) with error, source in
  <details>, and retry.
- globals.css (appended): @source for streamdown dist — its internal UI
  chrome (code blocks, mermaid containers, tables) was entirely unstyled
  because Tailwind v4 never scans node_modules; --color-sidebar → card; wide
  mermaid SVGs capped to the column; .katex-display scrolls.
- tests/render-markdown.test.tsx: 26 tests (transform unit + render). The
  math describe block in render-cards.test.tsx is updated to the new
  contract ($...$ now renders as literal text — pinned).
2026-08-22 09:38:54 +03:00