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:
2026-02-28 21:17:50 -05:00
parent 9e00901179
commit f8bab9ee33
18 changed files with 718 additions and 369 deletions

View File

@@ -19,7 +19,8 @@ type AppAction =
| { type: 'reorder'; ranking: string[] }
| { type: 'setMode'; mode: OptimizationMode }
| { type: 'pinCourse'; setId: string; courseId: string }
| { type: 'unpinCourse'; setId: string };
| { type: 'unpinCourse'; setId: string }
| { type: 'clearAll' };
function reducer(state: AppState, action: AppAction): AppState {
switch (action.type) {
@@ -34,6 +35,8 @@ function reducer(state: AppState, action: AppAction): AppState {
delete next[action.setId];
return { ...state, pinnedCourses: next };
}
case 'clearAll':
return { ...state, pinnedCourses: {} };
}
}
@@ -150,6 +153,7 @@ export function useAppState() {
const setMode = useCallback((mode: OptimizationMode) => dispatch({ type: 'setMode', mode }), []);
const pinCourse = useCallback((setId: string, courseId: string) => dispatch({ type: 'pinCourse', setId, courseId }), []);
const unpinCourse = useCallback((setId: string) => dispatch({ type: 'unpinCourse', setId }), []);
const clearAll = useCallback(() => dispatch({ type: 'clearAll' }), []);
return {
state,
@@ -162,5 +166,6 @@ export function useAppState() {
setMode,
pinCourse,
unpinCourse,
clearAll,
};
}