Improve analysis UX: algorithm explanations, skeleton loading, auto-expand achieved specs

- Replace terse one-line optimization mode descriptions with clearer multi-sentence
  explanations of how Maximize Count and Priority Order algorithms behave
- Add skeleton loading placeholders on course buttons while analysis is pending
- Auto-expand achieved specializations to show credit breakdown by default
- Add instructional subtitles to Course Selection and Specializations sections
- Make Clear and Clear All buttons more prominent with visible backgrounds
This commit is contained in:
2026-02-28 21:56:06 -05:00
parent 6af24d9270
commit 969d4ff5a9
10 changed files with 201 additions and 17 deletions

View File

@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useState, useEffect, useRef } from 'react';
import {
DndContext,
closestCenter,
@@ -180,7 +180,23 @@ interface SpecializationRankingProps {
}
export function SpecializationRanking({ ranking, result, onReorder }: SpecializationRankingProps) {
const [expanded, setExpanded] = useState<Set<string>>(new Set());
const [expanded, setExpanded] = useState<Set<string>>(() => new Set(result.achieved));
const prevAchievedRef = useRef(result.achieved);
useEffect(() => {
const prev = prevAchievedRef.current;
if (prev !== result.achieved) {
prevAchievedRef.current = result.achieved;
const newlyAchieved = result.achieved.filter((id) => !prev.includes(id));
if (newlyAchieved.length > 0) {
setExpanded((s) => {
const next = new Set(s);
for (const id of newlyAchieved) next.add(id);
return next;
});
}
}
}, [result.achieved]);
const sensors = useSensors(
useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
useSensor(TouchSensor, { activationConstraint: { delay: 150, tolerance: 5 } }),
@@ -217,7 +233,8 @@ export function SpecializationRanking({ ranking, result, onReorder }: Specializa
return (
<div>
<h2 style={{ fontSize: '16px', marginBottom: '8px' }}>Specializations</h2>
<h2 style={{ fontSize: '16px', marginBottom: '4px' }}>Specializations</h2>
<p style={{ fontSize: '12px', color: '#888', margin: '0 0 8px' }}>Drag or use arrows to rank your preferences. The optimizer uses this order to allocate credits.</p>
<div style={{ marginBottom: '8px', fontSize: '13px', color: '#666' }}>
{result.achieved.length > 0
? `${result.achieved.length} specialization${result.achieved.length > 1 ? 's' : ''} achieved`