69 lines
4.1 KiB
Markdown
69 lines
4.1 KiB
Markdown
## Context
|
|
|
|
The app is a React (Vite/TypeScript) single-page app with no external UI library. Courses are rendered as clickable buttons in `CourseSelection.tsx`. There is no existing tooltip or popover infrastructure. The app already handles responsive layout via a `useMediaQuery` hook.
|
|
|
|
Course descriptions and instructors come from a static PDF (`ref/J27 Electives-Course Descriptions.pdf`) plus one supplementary markdown file (`ref/inovation-and-design.md`). The data is stable per cohort (J27).
|
|
|
|
## Goals / Non-Goals
|
|
|
|
**Goals:**
|
|
- Show course description and instructor(s) inline via a popover triggered by an info icon
|
|
- Work identically on desktop and mobile (click/tap, no hover or long-press)
|
|
- Keep course description data separate from solver data structures
|
|
|
|
**Non-Goals:**
|
|
- Dynamic fetching of descriptions from an API
|
|
- Editing or updating descriptions at runtime
|
|
- Changing the Course type or solver logic
|
|
- Adding a third-party tooltip/popover library
|
|
|
|
## Decisions
|
|
|
|
### 1. Separate data file keyed by course ID
|
|
|
|
Store descriptions in `app/src/data/courseDescriptions.ts` as a `Record<string, { description: string; instructors: string[] }>` keyed by course ID.
|
|
|
|
**Why over extending Course type:** Descriptions are long strings unrelated to solver logic. Keeping them separate preserves readability of `courses.ts` and avoids polluting the `Course` interface used throughout the solver.
|
|
|
|
**Why key by course ID (not name):** The same course name can appear in multiple elective sets with different instructors (e.g., "Collaboration, Conflict and Negotiation" — Steve Blader in Spring, Elizabeth Morrison in Summer). Per-ID keying handles this correctly at the cost of some description duplication.
|
|
|
|
### 2. Info icon trigger (not hover/long-press)
|
|
|
|
An `(i)` icon button next to each course name, clickable on all platforms.
|
|
|
|
**Why over CSS hover tooltip:** Hover doesn't work on touch devices. A separate info icon avoids conflicting with the existing click-to-select behavior on the course button.
|
|
|
|
**Why over long-press on mobile:** Long-press is discoverable only if users know to try it. An explicit icon is universally obvious.
|
|
|
|
### 3. Pure CSS/React popover (no library)
|
|
|
|
Build the popover as a positioned `div` managed with React state. Close on: click outside (document listener), re-click icon, or Escape key.
|
|
|
|
**Why no library:** The app has zero UI dependencies beyond React. A single popover component doesn't justify adding one. The positioning logic is straightforward since popovers anchor to a known icon element.
|
|
|
|
### 4. Popover content layout
|
|
|
|
```
|
|
┌────────────────────────────────┐
|
|
│ Course Name │
|
|
│ Instructor(s): Name, Name │
|
|
│ ────────────────────────────── │
|
|
│ Description text, scrollable │
|
|
│ if longer than max-height... │
|
|
└────────────────────────────────┘
|
|
```
|
|
|
|
- Fixed max-width (~320px), max-height (~300px) with overflow scroll
|
|
- Instructor list shown as comma-separated
|
|
- Close button (X) in top-right corner
|
|
|
|
### 5. Event handling: stop propagation on info icon
|
|
|
|
The `(i)` icon click must call `e.stopPropagation()` to prevent the parent course button's `onClick` (which pins the course) from firing.
|
|
|
|
## Risks / Trade-offs
|
|
|
|
- **Description duplication across sets** — Same description text stored under multiple course IDs (e.g., `spr1-collaboration` and `sum1-collaboration`). Acceptable given the small dataset (~35 entries) and the need for per-ID instructor differentiation.
|
|
- **Popover positioning at screen edges** — A simple anchored popover could overflow the viewport on narrow screens. Mitigation: on mobile, render as a near-full-width card or use `position: fixed` centered overlay instead of anchored positioning.
|
|
- **Stale data if courses change** — Descriptions are hardcoded. If the course list changes for a future cohort, both `courses.ts` and `courseDescriptions.ts` need updating. This matches the existing pattern (all course data is static).
|