Wave-5 refinement round 3 (owner): SVG answer marks + uniform input sizes

- ✓/✗ in the answered card: replaced literal glyphs with lucide CheckIcon/
  XIcon (strokeWidth 2.5) inside a fixed size-4 flex box — text elements
  never carried the right size/vertical alignment, vectors do. Test pins
  updated (lucide-check/lucide-x classes).
- All user-typed INPUT text now matches markdown output: lh-prose class
  replaces the earlier font-prose (family-only) band-aid on the composer,
  question-dock text/thinking/Other fields, home topic input, model search
  box, and answered-card 'your thinking'/free-text records. lh-prose sets
  family+size (16.5px) so placeholders inherit correctly.
This commit is contained in:
amosblomqvist
2026-09-13 01:20:07 +03:00
parent f1433306db
commit d4212cecf2
6 changed files with 17 additions and 16 deletions
+8 -8
View File
@@ -1,5 +1,6 @@
"use client";
import { CheckIcon, XIcon } from "lucide-react";
import { cn } from "@/lib/utils";
import { MessageResponse } from "@/components/ai-elements/message";
import type { QuestionAnswerData } from "@/src/core";
@@ -58,20 +59,19 @@ export function AnsweredCard({ answer }: { answer: QuestionAnswerData }) {
)}
>
{isQuiz && (
// SVG icons, not glyphs — exactly one text-size box (size-4),
// vertically centered in the flex row (owner).
<span
aria-hidden
className={cn(
// Same visual size as the row text, vertically centered,
// colored like the verdict chips (owner).
"flex size-4 shrink-0 items-center justify-center text-sm font-semibold leading-none",
"flex size-4 shrink-0 items-center justify-center",
sel && key && "text-green-500",
sel && !key && "text-red-500",
!sel && key && "text-green-500",
)}
>
{sel && key && "✓"}
{sel && !key && "✗"}
{!sel && key && "✓"}
{key && <CheckIcon className="size-4" strokeWidth={2.5} />}
{sel && !key && <XIcon className="size-4" strokeWidth={2.5} />}
</span>
)}
<span className={cn(!sel && "text-muted-foreground")}>
@@ -94,7 +94,7 @@ export function AnsweredCard({ answer }: { answer: QuestionAnswerData }) {
</div>
)}
{answer.text && <div className="font-prose mt-2 whitespace-pre-wrap text-sm">“{answer.text}”</div>}
{answer.text && <div className="lh-prose mt-2 whitespace-pre-wrap">“{answer.text}”</div>}
{answer.dontKnow && isQuiz && <div className="mt-2 text-sm text-muted-foreground">Answered “I don't know”.</div>}
{answer.note && (
@@ -102,7 +102,7 @@ export function AnsweredCard({ answer }: { answer: QuestionAnswerData }) {
<span className="mb-0.5 block text-xxs font-medium uppercase tracking-wide text-muted-foreground">
Your thinking
</span>
<span className="font-prose block whitespace-pre-wrap text-sm text-foreground/90">{answer.note}</span>
<span className="lh-prose block whitespace-pre-wrap text-foreground/90">{answer.note}</span>
</div>
)}
+1 -1
View File
@@ -59,7 +59,7 @@ export function Composer({
placeholder="Ask, answer, or steer the lesson…"
autoFocus={autoFocus}
rows={1}
className="field-sizing-content font-prose max-h-48 min-h-10 flex-1 resize-none bg-transparent px-2.5 py-2 text-sm outline-none placeholder:text-muted-foreground"
className="field-sizing-content lh-prose max-h-48 min-h-10 flex-1 resize-none bg-transparent px-2.5 py-2 outline-none placeholder:text-muted-foreground"
/>
{verdict && !busy ? (
// The plan verdict (docs/probe-teach-split.md §4): accept
+1 -1
View File
@@ -82,7 +82,7 @@ export function Home() {
placeholder="What do you want to learn?"
autoFocus
rows={1}
className="field-sizing-content max-h-48 min-h-10 flex-1 resize-none bg-transparent px-2.5 py-2 text-sm outline-none placeholder:text-muted-foreground"
className="field-sizing-content lh-prose max-h-48 min-h-10 flex-1 resize-none bg-transparent px-2.5 py-2 outline-none placeholder:text-muted-foreground"
/>
<button
type="submit"
+1 -1
View File
@@ -198,7 +198,7 @@ export function ModelControl({
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search models…"
className="mb-1.5 w-full rounded-lg border bg-background px-2 py-1.5 text-foreground outline-none focus:ring-1 focus:ring-ring"
className="lh-prose mb-1.5 w-full rounded-lg border bg-background px-2 py-1.5 text-foreground outline-none focus:ring-1 focus:ring-ring"
/>
{error && <div className="mb-1.5 text-destructive">{error}</div>}
{!catalog && (
+3 -3
View File
@@ -387,7 +387,7 @@ function QuestionDockForm({
setSel((prev) => (prev.otherSelected ? prev : toggleOther(selectMode, prev)));
}}
placeholder="Type your own answer…"
className="font-prose w-full min-w-0 flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
className="lh-prose w-full min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground"
onClick={(e) => e.stopPropagation()}
/>
</div>
@@ -429,7 +429,7 @@ function QuestionDockForm({
}}
placeholder="Type your answer…"
rows={1}
className="field-sizing-content font-prose max-h-48 min-h-10 w-full resize-none bg-transparent px-2.5 py-2 text-sm outline-none placeholder:text-muted-foreground"
className="field-sizing-content lh-prose max-h-48 min-h-10 w-full resize-none bg-transparent px-2.5 py-2 outline-none placeholder:text-muted-foreground"
/>
) : (
<textarea
@@ -446,7 +446,7 @@ function QuestionDockForm({
placeholder="Why this answer? What are you unsure about? Say as much as you like — the teacher reads all of this."
rows={1}
className={cn(
"field-sizing-content font-prose max-h-48 w-full resize-none bg-transparent px-2.5 py-2 text-sm outline-none placeholder:text-muted-foreground/70",
"field-sizing-content lh-prose max-h-48 w-full resize-none bg-transparent px-2.5 py-2 outline-none placeholder:text-muted-foreground/70",
// Phase-scaled prominence: teaching invites depth,
// probing stays quick.
phase === "teach" ? "min-h-[4.5rem]" : "min-h-10",