Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

07 — Component Library (Exams Module)

Module-specific components on top of 00-shared/03_Component_Library.md (primitives like AppButton, AppTextField, AppDialog, AppDropdown, AppDatePicker, AppEmptyState, AppSkeleton are reused, never re-built). Each component lists variants, states, and token mapping. Tokens: Sp = 00-shared/02 §3, Ty §2, El §5, R §4, Mo §6, color roles §1.


1. ExamStatusBadge

PurposeRender the exam lifecycle state: draft, active, completed, published (examination.schema.ts:28-33)
Variantsdraft → neutral (surfaceVariant/onSurfaceVariant); active → primary; completed → secondary; published → tertiary + Icons.verified
Statesicon + label always (never color-only, 00-shared/09); loading → skeleton chip
TokenslabelSmall (Ty), radius r-full, padding Sp.4/Sp.8, gap Sp.4
A11ySemantics(label: 'Status: published')

2. ExamTypeChip

PurposeShow exam type: midterm, final, unit_test, quarterly, other (examination.schema.ts:15-20); labels: "Midterm", "Final", "Unit test", "Quarterly", "Other"
Variantsselected (filter mode, primaryContainer) / static (informational, surfaceContainerHighest)
TokenslabelMedium, r-full, Sp.4/Sp.10

3. ExamCard (S1 list row)

Dataname, type, startDate, endDate, status, academicYearId (examination.schema.ts:9-36); derived: slots count + marked/total (from coverage queries)
Layout2-line header + meta row + footer row; inkWell whole-card tap → S2
Statesdefault / pressed (stateLayer primary 8%) / hover (desktop tint) / disabled (not used in list)
TokenssurfaceContainerLow, r-lg, e-1, padding Sp.16, gaps Sp.8/Sp.12
A11ySemantics(button) with full sentence label (§06 §1)

4. ExamSubjectCard (slot row, S2)

DatasubjectId, classId, date, startTime, endTime, maximumMarks, passingMarks (examination-subject.schema.ts:9-31); coverage marked/total
Layout[subject icon] Subject · Class / date HH:mm–HH:mm / Max 100 · Pass 33 / progress (coverage) / chevron
Variantswith-coverage (progress bar from result counts) / without (slots without marks loaded); selected (tablet rail)
Statestap → S3; long-press → "Open marks" context menu (tablet)
TokenssurfaceContainer, r-md, padding Sp.12/Sp.16; progress 4 dp primary/tertiary when full
A11ySemantics(button, label: 'Subject, Class, date, time, max marks, N of M marked')

5. MarksRow (S3 roster row)

Datastudent (roster, resolved from classId via Students module) + result marksObtained, grade?, remarks?, publishedAt? (examination-result.schema.ts:15-25)
Layoutavatar initials · name/meta · MarksTextField (digits, max digits of maximumMarks) · optional grade chip · save-state icon
Statesunsaved (editing, outline primary) / saving (inline spinner) / saved (check tertiary, Mo.fast) / failed (shake Mo.shake, error icon, "Retry") / queued-offline (dashed border, cloud icon) / published (lock chip "published" — publishedAt set)
Tokensrow surfaceContainerLow, gap Sp.12; field width 96 dp, labelLarge mono tabular
A11yrow semantics label with marks vs max; inline error announced

6. MarksSummaryBar (S3 coverage)

Datamarked/total + queued/failed counts (cubit-derived, 13_State_Management.md)
Layoutlabel "118 of 120 marked" + animated bar; below: "2 offline · 1 failed — Retry" line
Statesidle / saving / offline (dashed overlay) / complete (100%, tertiary)
Tokensheight 8 dp bar, r-full, primary; labelMedium; Semantics(liveRegion)

7. GradeChip

Datagrade? free text from EnterMarksDto (examination-subject.dto.ts:57-60) — client never computes per-subject grades (OQ-9)
Variantsfilled (grade present, secondaryContainer) / absent (tap → grade sheet)
TokenslabelMedium, r-full, padding Sp.4/Sp.8

8. CoverageTile (S2 coverage tab)

Dataslot + marked/total via GET /results/exam-subject/:id; max/pass marks
Layoutsubject · class · bar · "42/45" · "Max 100 · Pass 33"
Statesnone / partial / complete / no-marks (0 of N)
TokenssurfaceContainer, r-md, padding Sp.12

9. PublishButton + PublishDialog (S2/S5)

PublishButtonFilledButton.tonal tertiary, label "Publish results", icon campaign; states: enabled (status ≠ published) / disabled (published — hidden instead) / submitting (spinner)
PublishDialogAppDialog wrapper (§06 §5): warning icon, coverage recap list, Cancel / Publish actions, non-dismissable while submitting
Tokensdialog width ≤ 480 dp, r-lg, El-e3

10. SlotHeaderCard (S3 top)

Datasubject/class names, date, startTimeendTime (HH:mm strings, examination-subject.schema.ts:18-25), maximumMarks, passingMarks
Warning statepassingMarks > maximumMarks → tertiary banner "Pass marks exceed max marks" (invalid config, OQ-6)
TokenssurfaceContainerLow, r-lg, e-1, padding Sp.16

11. ResultRowCard (S6)

Dataresult doc (marksObtained, grade?, remarks?, publishedAt?, examination-result.schema.ts:15-25); subject/exam resolved client-side (OQ-9)
Layoutsubject · marks/max · grade chip · published date · remarks preview (2-line clamp)
TokenssurfaceContainerLow, r-md, padding Sp.12/Sp.16

12. ReportCardTable (S7)

Datasubjects[], totalMarksObtained, totalMaximumMarks, percentage, overallGrade, generatedAt (result.service.ts:8-26, 88-97)
Layoutphone: stacked rows; ≥840 dp: real table (Subject / Marks / Grade / Remarks) + totals row + overall card
Statesrow missing mark → "0" + muted "not marked" (payload can't distinguish, result.service.ts:70); empty grade → "—"
Tokensheader labelLarge onSurfaceVariant; numbers mono tabular; r-lg card wrap

13. GradeBadge (S7 overall)

DataoverallGrade letter (A+/A/B+/B/C/D/F — result.service.ts:130-138)
TokensdisplaySmall letter, r-lg padding Sp.8/Sp.16, primaryContainer; caption labelMedium "80–89%"
A11ySemantics(label: 'Grade A, 80 to 89 percent')

Reuse summary

NeedComponent source
Buttons, text fields, dialogs, dropdowns, date pickers, skeletons, empty/error/offline states00-shared/03 primitives
Motion, haptics00-shared/08_Interaction_&_Motion.md (Mo.fast/base/shake)
Accessibility baseline00-shared/09_Accessibility_Baseline.md
Forms & validation patterns08_Form_Specifications.md (module)