UI improvements: responsive layout, unified panels, credit legend
- 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
This commit is contained in:
83
openspec/changes/ui-improvements/design.md
Normal file
83
openspec/changes/ui-improvements/design.md
Normal file
@@ -0,0 +1,83 @@
|
||||
## 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.
|
||||
Reference in New Issue
Block a user