Add CSS transitions and animations for smooth UI interactions

Animate course set pin/unpin with cross-fade content swap, credit bar
width changes, status badge color transitions, expand/collapse panels
(CreditLegend, AllocationBreakdown), mode toggle switching, and
ModeComparison banner fade. Specialization rows flash on credit/status
changes. Threshold markers animate position. All animations respect
prefers-reduced-motion.
This commit is contained in:
2026-02-28 22:46:11 -05:00
parent 7940050196
commit 7a8330e205
11 changed files with 318 additions and 19 deletions

View File

@@ -51,11 +51,13 @@ function ElectiveSet({
return (
<div
style={{
border: isPinned ? '1px solid #3b82f6' : '1px dashed #ccc',
border: isPinned ? '1px solid #3b82f6' : '1px solid #ccc',
borderStyle: isPinned ? 'solid' : 'dashed',
borderRadius: '8px',
padding: '12px',
marginBottom: '8px',
background: isPinned ? '#eff6ff' : '#fafafa',
transition: 'border-color 200ms, background-color 200ms',
}}
>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
@@ -78,11 +80,25 @@ function ElectiveSet({
</button>
)}
</div>
{isPinned ? (
{/* Pinned view */}
<div style={{
maxHeight: isPinned ? '40px' : '0',
opacity: isPinned ? 1 : 0,
overflow: 'hidden',
transition: 'max-height 250ms ease-out, opacity 200ms',
}}>
<div style={{ fontSize: '14px', fontWeight: 600, color: '#1e40af' }}>
{pinnedCourse?.name}
</div>
) : (
</div>
{/* Course list view */}
<div style={{
maxHeight: isPinned ? '0' : '500px',
opacity: isPinned ? 0 : 1,
overflow: 'hidden',
pointerEvents: isPinned ? 'none' : 'auto',
transition: 'max-height 250ms ease-out, opacity 200ms',
}}>
<div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>
{courses.map((course) => {
const ceiling = ceilingMap.get(course.id);
@@ -136,7 +152,7 @@ function ElectiveSet({
);
})}
</div>
)}
</div>
</div>
);
}