feat: add ShortAnswer and MathInput renderers

This commit is contained in:
LaurensBartelds committed 2026-04-21 21:41:37 +02:00
1 parent 2a59f13870
commit 82ba53da0e
2 files changed
+75

No files matched your search

@@ -0,0 +1,45 @@
import { useState, useEffect } from 'react'
import katex from 'katex'
import type { Question } from '../../types'
interface Props {
q: Question
value: string | null | undefined
onChange: (val: string) => void
locked?: boolean
}
// The KaTeX preview uses innerHTML: KaTeX controls all output, making this safe.
export default function MathInput({ value = '', onChange, locked }: Props) {
const [preview, setPreview] = useState('')
useEffect(() => {
if (!value) { setPreview(''); return }
try {
setPreview(katex.renderToString(value, { throwOnError: false, displayMode: false }))
} catch {
setPreview('')
}
}, [value])
return (
<div className="answer-input-wrap">
<input
className="input mono"
type="text"
value={value ?? ''}
onChange={(e) => onChange(e.target.value)}
placeholder="LaTeX, e.g. 2x\ln x + x"
disabled={locked}
autoComplete="off"
spellCheck={false}
/>
<div className="math-preview">
<span className="math-preview-label">Preview</span>
{preview
? <span dangerouslySetInnerHTML={{ __html: preview }} />
: <span className="faint" style={{ fontSize: 13 }}>Live LaTeX preview appears here</span>}
</div>
</div>
)
}
@@ -0,0 +1,30 @@
import type { Question } from '../../types'
interface Props {
q: Question
value: string | null | undefined
onChange: (val: string) => void
locked?: boolean
}
export default function ShortAnswer({ q, value = '', onChange, locked }: Props) {
return (
<div className="answer-input-wrap">
<input
className="input"
type="text"
value={value ?? ''}
onChange={(e) => onChange(e.target.value)}
placeholder="Type your answer…"
disabled={locked}
autoComplete="off"
spellCheck={q.type === 'translation'}
/>
{q.type === 'translation' && q.targetLanguage && (
<div className="faint mono" style={{ fontSize: 11 }}>
Answer in {q.targetLanguage}
</div>
)}
</div>
)
}