CourseCard.jsx UI component
The atomic unit of the UI. A draggable course tile rendered in three contexts: inside a semester row, inside the course bank, and inside the GradPanel requirement tree. Appearance adapts to context and viewport size.
id (courseId), inSem (bool), semId (when placed)Three rendering modes
| Context | Layout | Shows |
|---|---|---|
| Semester (desktop) | Tall card, full width | Color stripe, code, title, SH badge, NUPath tags, schedule badge, warning icons |
| Semester (phone) | Compact row | Code + SH only. No title (saves space). |
| Bank | Narrow row | Code + star button. No SH/NUPath (shown in InfoPanel when selected). |
Warning icons
Three types of inline warnings shown on cards in semester rows:
- ⚠ Not offered: Course is placed in a semester type it's not offered in (e.g. a fall-only course placed in Spring). Derived from
course.offeredFalletc. vs the semester type. - ⚡ Coreq violation: A corequisite is missing from the same semester. Read from
coreqViolationsin context. - ! Prereq unsatisfied: A prerequisite is missing or in a later semester. Read from
prereqViolationsin context.
Additionally, a yellow border appears when prereqViolations.has(id) (the "misplaced" highlight in the legend).
Variable-credit editing
If course.shMin !== course.shMax, the SH badge becomes clickable. Clicking it enters edit mode: a small inline <input type="number"> replaces the badge. On blur/enter, the value is stored in shOverrides[id] in context (clamped to [shMin, shMax]).
Selection and dimming
Clicking a card sets selectedId = id in context. This opens InfoPanel and triggers RelationLines to draw SVG lines. All other cards receive reduced opacity (0.4) to dim them. The selected card gets a highlighted border.
Drag handling
On touch devices, the same flow is driven by touchstart/touchmove/touchend events with a ghost element that follows the finger. The ghost is a clone of the card appended to document.body.