- Add responsive 2-panel layout (mobile single-col, tablet/desktop grid) - Unify specialization ranking with credit bars, status badges, and expandable allocation breakdowns (remove standalone ResultsDashboard) - Inline decision tree ceiling data on course buttons with spec counts - Add Clear All button to reset all course selections - Add collapsible CreditLegend explaining bars, badges, and limits - Extract ModeComparison and MutualExclusionWarnings to Notifications - Add useMediaQuery hook with matchMedia-based breakpoint detection
84 lines
5.7 KiB
Markdown
84 lines
5.7 KiB
Markdown
## Context
|
||
|
||
The app currently uses a fixed 3-column grid layout (`280px 1fr 1fr`): specialization ranking on the left, course selection in the middle, results dashboard on the right. This breaks completely on mobile — it requires a minimum ~960px viewport. Specialization progress (credit bars, status badges) lives in a separate Results panel from the ranking list, forcing users to cross-reference two panels. The decision tree is buried at the bottom of the Results panel, disconnected from the course selection it's meant to guide.
|
||
|
||
Current component structure:
|
||
- `App.tsx` — 3-column grid, wires state to components
|
||
- `SpecializationRanking.tsx` — drag-and-drop ranking with status badges (no credit bars)
|
||
- `CourseSelection.tsx` — elective sets grouped by term, pin/unpin per set
|
||
- `ResultsDashboard.tsx` — credit bars, allocation breakdown, decision tree, mode comparison, mutual exclusion warnings
|
||
- `ModeToggle.tsx` — toggle between maximize-count and priority-order
|
||
- `state/appState.ts` — useReducer with reorder/setMode/pinCourse/unpinCourse actions
|
||
|
||
## Goals / Non-Goals
|
||
|
||
**Goals:**
|
||
- Usable on mobile phones (360px+), tablets, and desktops
|
||
- Single specialization panel that shows rank, reorder controls, status, and credit progress together
|
||
- Course selection UI that shows decision tree ceiling outcomes inline with each course option
|
||
- Clear all selections with one action
|
||
- New users can understand the credit bars and status badges without external docs
|
||
|
||
**Non-Goals:**
|
||
- Complete visual redesign / theming — keep existing colors and inline style approach
|
||
- Offline/PWA support
|
||
- Changing the optimization engine or data layer
|
||
- Touch-based drag reordering on mobile (arrow buttons already work; drag is a nice-to-have that already has TouchSensor)
|
||
|
||
## Decisions
|
||
|
||
### 1. Responsive layout: CSS media queries via inline styles with a `useMediaQuery` hook
|
||
|
||
Use a custom `useMediaQuery` hook that returns the current breakpoint. App.tsx switches between layouts:
|
||
- **Mobile (<640px)**: Single column, stacked vertically. Specializations panel, then course panel. Each is full-width.
|
||
- **Tablet (640–1024px)**: Two columns, specializations left (300px), courses right (flex).
|
||
- **Desktop (>1024px)**: Same two columns with more breathing room.
|
||
|
||
Why not CSS classes / a CSS framework: The entire app uses inline styles. Adding a CSS framework for just responsive layout would be inconsistent. A hook-based approach keeps the pattern uniform and avoids adding dependencies.
|
||
|
||
### 2. Unified specialization panel: Extend `SpecializationRanking` to include credit bars
|
||
|
||
Merge the per-spec progress display from `ResultsDashboard` directly into `SpecializationRanking`'s `SortableItem`. Each row becomes:
|
||
```
|
||
[▲▼] [⠿] [rank] [name] [credits/9.0] [status badge]
|
||
[====credit bar====]
|
||
```
|
||
|
||
The row is clickable to expand allocation breakdown (for achieved specs). This replaces the top section of `ResultsDashboard`.
|
||
|
||
`ResultsDashboard` is reduced to just global notifications: mode comparison banner, mutual exclusion warnings, and the summary count — displayed above the specialization panel in the layout, not as a separate column.
|
||
|
||
### 3. Unified course panel: Inline decision tree data per elective set
|
||
|
||
Extend `ElectiveSet` to accept optional ceiling analysis data. When an open set has tree results, each course button shows its ceiling outcome on the right:
|
||
```
|
||
[Mergers & Acquisitions 3 specs (BNK, FIN, LCM)]
|
||
[Digital Strategy 3 specs (BNK, FIN, LCM)]
|
||
```
|
||
|
||
The standalone `DecisionTree` component at the bottom of ResultsDashboard is removed. The "high impact" indicator moves to the set header. Loading state shows a subtle spinner on sets still being analyzed.
|
||
|
||
### 4. Clear all: New reducer action + button in course selection header
|
||
|
||
Add a `clearAll` action to the reducer that resets `pinnedCourses` to `{}`. Place a "Clear All" button in the `CourseSelection` header, visible only when at least one course is pinned. Styled as a small text button (consistent with the per-set "clear" buttons).
|
||
|
||
### 5. Credit explainer: Collapsible legend above the specialization panel
|
||
|
||
Add a small "How to read this" toggle that expands to show:
|
||
- What the credit bar segments mean (dark = allocated from pinned courses, light = potential from open sets, tick mark = 9-credit threshold)
|
||
- What each status badge means (achieved, achievable, missing required course, unreachable)
|
||
- Brief note that max 3 specializations can be achieved (30 credits / 9 per spec)
|
||
|
||
Collapsed by default to avoid visual noise for returning users. State is not persisted (resets on reload).
|
||
|
||
### 6. Notifications area: Mode comparison and warnings float above the spec panel
|
||
|
||
`ModeComparison` and `MutualExclusionWarnings` render as banners at the top of the page (below the header/mode toggle, above the specialization panel). They're not tied to a specific column.
|
||
|
||
## Risks / Trade-offs
|
||
|
||
- **Inline responsive styles are verbose** → Accepted; keeps the project consistent and avoids adding a CSS framework for one change. The `useMediaQuery` hook keeps conditional logic manageable.
|
||
- **Unified spec rows are denser on mobile** → Mitigated by making credit bar slim (already 6px) and keeping text sizes small. Allocation breakdown is tap-to-expand.
|
||
- **Decision tree data arrives asynchronously** → Course buttons render immediately without ceiling data; outcomes appear progressively as the worker completes each set. No layout shift since the ceiling text is right-aligned and fits on the same line.
|
||
- **14 spec rows + 12 elective sets is a lot of vertical content on mobile** → Accepted trade-off; all content is important. The two-section layout (specs then courses) gives a clear reading order. Users can scroll naturally.
|