07 — Component Library (Exams Module)
- 1. ExamStatusBadge
- 2. ExamTypeChip
- 3. ExamCard (S1 list row)
- 4. ExamSubjectCard (slot row, S2)
- 5. MarksRow (S3 roster row)
- 6. MarksSummaryBar (S3 coverage)
- 7. GradeChip
- 8. CoverageTile (S2 coverage tab)
- 9. PublishButton + PublishDialog (S2/S5)
- 10. SlotHeaderCard (S3 top)
- 11. ResultRowCard (S6)
- 12. ReportCardTable (S7)
- 13. GradeBadge (S7 overall)
- Reuse summary
Module-specific components on top of 00-shared/03_Component_Library.md (primitives like
AppButton,AppTextField,AppDialog,AppDropdown,AppDatePicker,AppEmptyState,AppSkeletonare 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
| Purpose | Render the exam lifecycle state: draft, active, completed, published (examination.schema.ts:28-33) |
| Variants | draft → neutral (surfaceVariant/onSurfaceVariant); active → primary; completed → secondary; published → tertiary + Icons.verified |
| States | icon + label always (never color-only, 00-shared/09); loading → skeleton chip |
| Tokens | labelSmall (Ty), radius r-full, padding Sp.4/Sp.8, gap Sp.4 |
| A11y | Semantics(label: 'Status: published') |
2. ExamTypeChip
| Purpose | Show exam type: midterm, final, unit_test, quarterly, other (examination.schema.ts:15-20); labels: "Midterm", "Final", "Unit test", "Quarterly", "Other" |
| Variants | selected (filter mode, primaryContainer) / static (informational, surfaceContainerHighest) |
| Tokens | labelMedium, r-full, Sp.4/Sp.10 |
3. ExamCard (S1 list row)
| Data | name, type, startDate, endDate, status, academicYearId (examination.schema.ts:9-36); derived: slots count + marked/total (from coverage queries) |
| Layout | 2-line header + meta row + footer row; inkWell whole-card tap → S2 |
| States | default / pressed (stateLayer primary 8%) / hover (desktop tint) / disabled (not used in list) |
| Tokens | surfaceContainerLow, r-lg, e-1, padding Sp.16, gaps Sp.8/Sp.12 |
| A11y | Semantics(button) with full sentence label (§06 §1) |
4. ExamSubjectCard (slot row, S2)
| Data | subjectId, 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 |
| Variants | with-coverage (progress bar from result counts) / without (slots without marks loaded); selected (tablet rail) |
| States | tap → S3; long-press → "Open marks" context menu (tablet) |
| Tokens | surfaceContainer, r-md, padding Sp.12/Sp.16; progress 4 dp primary/tertiary when full |
| A11y | Semantics(button, label: 'Subject, Class, date, time, max marks, N of M marked') |
5. MarksRow (S3 roster row)
| Data | student (roster, resolved from classId via Students module) + result marksObtained, grade?, remarks?, publishedAt? (examination-result.schema.ts:15-25) |
| Layout | avatar initials · name/meta · MarksTextField (digits, max digits of maximumMarks) · optional grade chip · save-state icon |
| States | unsaved (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) |
| Tokens | row surfaceContainerLow, gap Sp.12; field width 96 dp, labelLarge mono tabular |
| A11y | row semantics label with marks vs max; inline error announced |
6. MarksSummaryBar (S3 coverage)
| Data | marked/total + queued/failed counts (cubit-derived, 13_State_Management.md) |
| Layout | label "118 of 120 marked" + animated bar; below: "2 offline · 1 failed — Retry" line |
| States | idle / saving / offline (dashed overlay) / complete (100%, tertiary) |
| Tokens | height 8 dp bar, r-full, primary; labelMedium; Semantics(liveRegion) |
7. GradeChip
| Data | grade? free text from EnterMarksDto (examination-subject.dto.ts:57-60) — client never computes per-subject grades (OQ-9) |
| Variants | filled (grade present, secondaryContainer) / absent (tap → grade sheet) |
| Tokens | labelMedium, r-full, padding Sp.4/Sp.8 |
8. CoverageTile (S2 coverage tab)
| Data | slot + marked/total via GET /results/exam-subject/:id; max/pass marks |
| Layout | subject · class · bar · "42/45" · "Max 100 · Pass 33" |
| States | none / partial / complete / no-marks (0 of N) |
| Tokens | surfaceContainer, r-md, padding Sp.12 |
9. PublishButton + PublishDialog (S2/S5)
| PublishButton | FilledButton.tonal tertiary, label "Publish results", icon campaign; states: enabled (status ≠ published) / disabled (published — hidden instead) / submitting (spinner) |
| PublishDialog | AppDialog wrapper (§06 §5): warning icon, coverage recap list, Cancel / Publish actions, non-dismissable while submitting |
| Tokens | dialog width ≤ 480 dp, r-lg, El-e3 |
10. SlotHeaderCard (S3 top)
| Data | subject/class names, date, startTime–endTime (HH:mm strings, examination-subject.schema.ts:18-25), maximumMarks, passingMarks |
| Warning state | passingMarks > maximumMarks → tertiary banner "Pass marks exceed max marks" (invalid config, OQ-6) |
| Tokens | surfaceContainerLow, r-lg, e-1, padding Sp.16 |
11. ResultRowCard (S6)
| Data | result doc (marksObtained, grade?, remarks?, publishedAt?, examination-result.schema.ts:15-25); subject/exam resolved client-side (OQ-9) |
| Layout | subject · marks/max · grade chip · published date · remarks preview (2-line clamp) |
| Tokens | surfaceContainerLow, r-md, padding Sp.12/Sp.16 |
12. ReportCardTable (S7)
| Data | subjects[], totalMarksObtained, totalMaximumMarks, percentage, overallGrade, generatedAt (result.service.ts:8-26, 88-97) |
| Layout | phone: stacked rows; ≥840 dp: real table (Subject / Marks / Grade / Remarks) + totals row + overall card |
| States | row missing mark → "0" + muted "not marked" (payload can't distinguish, result.service.ts:70); empty grade → "—" |
| Tokens | header labelLarge onSurfaceVariant; numbers mono tabular; r-lg card wrap |
13. GradeBadge (S7 overall)
| Data | overallGrade letter (A+/A/B+/B/C/D/F — result.service.ts:130-138) |
| Tokens | displaySmall letter, r-lg padding Sp.8/Sp.16, primaryContainer; caption labelMedium "80–89%" |
| A11y | Semantics(label: 'Grade A, 80 to 89 percent') |
Reuse summary
| Need | Component source |
|---|---|
| Buttons, text fields, dialogs, dropdowns, date pickers, skeletons, empty/error/offline states | 00-shared/03 primitives |
| Motion, haptics | 00-shared/08_Interaction_&_Motion.md (Mo.fast/base/shake) |
| Accessibility baseline | 00-shared/09_Accessibility_Baseline.md |
| Forms & validation patterns | 08_Form_Specifications.md (module) |