draw every kind of textbook figure, lock math text left-to-right, student-first family screen

- src/diagram: plane (constructed points, graphs with computed roots, vertex,
  extrema, tangent, asymptotes, piecewise limits, regions, rotations and
  reflections, line from ax + by = c), number line with intervals and stacked
  fractions, solids with hidden edges, bar/line/pie charts, sign tables, Venn,
  arrow mappings, probability trees, fraction bars and mixed numbers, grids,
  groups, clock. Pure-math text is bidi-overridden: Persian digits used to turn
  3 × 4 = 12 into 12 = 4 × 3 even with dir=ltr.
- MathText locks math runs inside Persian sentences in chat bubbles and figure
  captions, so -1 no longer shows as 1-.
- Family screen: a student sees only the invite-code form; the parent form is
  behind a link.
- Dev-only diagram gallery at ?gallery (not in the production build).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-28 23:24:50 +03:30
parent 355bae7035
commit ec4c844531
18 changed files with 2165 additions and 419 deletions

View File

@@ -219,25 +219,10 @@ export interface ConversationMessage {
diagram?: Diagram | null;
}
/* ─── شکلِ پاسخِ دستیار (بک‌اند: rag/services/diagram.py) ─────────────────── */
/* ─── شکلِ پاسخِ دستیار: شِمایش در src/diagram/types.ts ─────────────────── */
export type DiagramRef = string | [number, number];
export type DiagramPointDef = [number, number] | { polar: [number, number]; from?: DiagramRef };
export type DiagramItem =
| { type: 'circle'; center: DiagramRef; r: number; label?: string }
| { type: 'segment' | 'arrow'; from: DiagramRef; to: DiagramRef; label?: string }
| { type: 'line'; through: [DiagramRef, DiagramRef]; label?: string }
| { type: 'angle' | 'rightAngle'; vertex: DiagramRef; from: DiagramRef; to: DiagramRef; label?: string }
| { type: 'polygon'; points: DiagramRef[]; label?: string }
| { type: 'point'; point: DiagramRef; label?: string }
| { type: 'function'; expr: string; from: number; to: number; label?: string }
| { type: 'text'; at: [number, number]; text: string };
export type Diagram =
| { kind: 'plane'; title: string; axes: boolean; points: Record<string, DiagramPointDef>; items: DiagramItem[] }
| { kind: 'numberline'; title: string; min: number; max: number; points: { at: number; label: string }[]; jumps: { from: number; to: number; label: string }[] }
| { kind: 'fraction'; title: string; shape: 'circle' | 'rect'; parts: number; shaded: number };
import type { DiagramSpec } from '@/diagram/types';
export type Diagram = DiagramSpec;
export interface NotificationItem {
id: number;