MathText display: formula in the middle of a Persian sentence gets its own centered line (quiz and lessons)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,7 +33,15 @@ const EDGE_END = /[\s،؛:!؟«»"'.=]+$/;
|
||||
// سمتِ خودشان میکشیدند، پس فهرست باز برعکس میشد.
|
||||
const LTR = { unicodeBidi: 'isolate-override', direction: 'ltr' } as const;
|
||||
|
||||
export function MathText({ text: raw }: { text: string }) {
|
||||
// فرمولِ «واقعی» (نه عددِ تنها): نمادِ رابطه یا عمل دارد و دستِکم چهار نویسه است.
|
||||
const FORMULA = /[=<>≤≥≠∈∉⊂⊆∪∩+×÷^√∑∫]|[0-9۰-۹A-Za-z)][\s]*[−\-/][\s]*[0-9۰-۹A-Za-z(]/;
|
||||
|
||||
/**
|
||||
* `display`: فرمولِ وسطِ جملهی فارسی در خطِ جدا و وسطچین مینشیند (سوالها و درسها)، تا
|
||||
* چشم وسطِ فرمول به خطِ بعد نیفتد. عددِ تنها و عبارتِ کوتاهِ بدونِ نمادِ عمل داخلِ جمله میماند.
|
||||
* آزموده نشده: صفحهی واقعیِ اپ در Chrome و Safari؛ فقط منطقِ تشخیص با نمونههای بانک سنجیده شد.
|
||||
*/
|
||||
export function MathText({ text: raw, display = false }: { text: string; display?: boolean }) {
|
||||
const text = plainPersian(plainMath(raw));
|
||||
const out: React.ReactNode[] = [];
|
||||
const depth = bracketDepth(text);
|
||||
@@ -56,7 +64,13 @@ export function MathText({ text: raw }: { text: string }) {
|
||||
run = edge.run;
|
||||
if (!run || !HAS_MATH.test(run)) continue;
|
||||
out.push(text.slice(last, start + head.length));
|
||||
const before = text.slice(0, start + head.length), after = text.slice(start + head.length + run.length);
|
||||
const inSentence = new RegExp(`[${LETTER}]`).test(before) || new RegExp(`[${LETTER}]`).test(after);
|
||||
if (display && inSentence && run.trim().length >= 4 && FORMULA.test(run) && depth[start + head.length] === 0) {
|
||||
out.push(<span key={i++} style={{ ...LTR, display: 'block', textAlign: 'center', margin: '4px 0', fontWeight: 800 }}>{run}</span>);
|
||||
} else {
|
||||
out.push(<span key={i++} style={LTR}>{run}</span>);
|
||||
}
|
||||
last = start + head.length + run.length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,17 +28,17 @@ export function parseNumbered(text: string): { lead: string; items: string[] } |
|
||||
|
||||
export function StepText({ text, color, className = '' }: { text: string; color: string; className?: string }) {
|
||||
const list = parseNumbered(text);
|
||||
if (!list) return <p className={`whitespace-pre-line ${className}`}><MathText text={text} /></p>;
|
||||
if (!list) return <p className={`whitespace-pre-line ${className}`}><MathText text={text} display /></p>;
|
||||
return (
|
||||
<div className={className}>
|
||||
{list.lead && <p className="mb-2 whitespace-pre-line"><MathText text={list.lead} /></p>}
|
||||
{list.lead && <p className="mb-2 whitespace-pre-line"><MathText text={list.lead} display /></p>}
|
||||
<ol className="flex flex-col gap-2.5">
|
||||
{list.items.map((item, i) => (
|
||||
<li key={i} className="flex gap-2.5">
|
||||
<span className="mt-0.5 flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full text-xs font-black text-white" style={{ backgroundColor: color }}>
|
||||
{toFa(i + 1)}
|
||||
</span>
|
||||
<span className="flex-1 whitespace-pre-line"><MathText text={item} /></span>
|
||||
<span className="flex-1 whitespace-pre-line"><MathText text={item} display /></span>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
|
||||
@@ -81,7 +81,7 @@ export function LessonScreen({ lessonId, nodeId }: { lessonId: number; nodeId?:
|
||||
<span className="flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full text-xs font-black text-white" style={{ backgroundColor: color }}>
|
||||
{toFa(i + 1)}
|
||||
</span>
|
||||
<span className="flex-1 whitespace-pre-line"><MathText text={step} />{figs('step', i)}</span>
|
||||
<span className="flex-1 whitespace-pre-line"><MathText text={step} display />{figs('step', i)}</span>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
|
||||
@@ -345,7 +345,7 @@ export function QuizScreen({ lessonId, nodeId }: { lessonId?: number; nodeId?: s
|
||||
<div className="mb-2 flex items-center justify-between">
|
||||
<span className="text-xs font-medium text-muted">سوال {toFa(index + 1)}</span>
|
||||
</div>
|
||||
<h2 className="whitespace-pre-line text-base font-bold leading-8 text-ink"><MathText text={question.prompt} /></h2>
|
||||
<h2 className="whitespace-pre-line text-base font-bold leading-8 text-ink"><MathText text={question.prompt} display /></h2>
|
||||
{question.figure ? <div className="mt-3"><Diagram spec={question.figure} /></div> : null}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user