On mobile, the single-column layout makes it easy to lose context when scrolling between the specializations and course selection panels. This adds two floating banners that appear via IntersectionObserver: - Top banner: summarizes specialization statuses (achieved/achievable/missing/unreachable) - Bottom banner: shows course selection progress (N/12 selected) Both slide in/out with CSS transitions and scroll to their respective sections on tap. Only rendered on mobile viewports (max-width: 639px).
2.3 KiB
2.3 KiB
1. Export STATUS_STYLES
- 1.1 Export
STATUS_STYLESfromSpecializationRanking.tsxso it can be imported by the banner component
2. Create MobileStatusBanner component
- 2.1 Create
app/src/components/MobileStatusBanner.tsxwith props:statuses: Record<string, SpecStatus>,visible: boolean,onTap: () => void - 2.2 Implement status count logic — loop over the statuses record to count each category (achieved, achievable, missing_required, unreachable)
- 2.3 Render four color-coded badges using
STATUS_STYLEScolors, each showing"{count} {label}"(display all categories including zero counts) - 2.4 Style the banner:
position: fixed,top: 0,left: 0,width: 100%,z-index: 1000, white background with bottom border, compact height (~40px) - 2.5 Implement slide animation: always mounted, use
transform: translateY(-100%)when hidden vstranslateY(0)when visible,transition: transform 200ms ease-out - 2.6 Attach
onClickhandler to the banner root element that callsonTap
3. Integrate into App.tsx
- 3.1 Add a
refto the specializations wrapper<div>inApp.tsx(the div containingCreditLegendandSpecializationRanking) - 3.2 Add IntersectionObserver logic: observe the specializations ref, set a
bannerVisiblestate totruewhen the section is not intersecting,falsewhen it is - 3.3 Gate the observer and banner on
isMobile— only create the observer and render the banner when on mobile breakpoint - 3.4 Mount
<MobileStatusBanner>at the top of the App return (before<h1>), passingstatuses={optimizationResult.statuses},visible={bannerVisible && isMobile}, andonTapthat callsspecSectionRef.current.scrollIntoView({ behavior: 'smooth' }) - 3.5 Clean up the IntersectionObserver in the useEffect return (disconnect on unmount or when isMobile changes)
4. Test
- 4.1 Verify banner appears on mobile viewport when scrolling past specializations
- 4.2 Verify banner hides when scrolling back up to specializations
- 4.3 Verify banner does not render on tablet/desktop viewports
- 4.4 Verify tapping the banner scrolls back to the specializations section
- 4.5 Verify status counts update reactively when course selections change while banner is visible
- 4.6 Verify badge colors match the specialization list status badges