Files
Bill Ballou 7940050196 Add mobile floating banners for specialization status and course selection progress
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).
2026-02-28 22:27:07 -05:00

1.8 KiB

1. Create MobileCourseBanner component

  • 1.1 Create app/src/components/MobileCourseBanner.tsx with props: selectedCount: number, totalSets: number, visible: boolean, onTap: () => void
  • 1.2 Render "{selectedCount} / {totalSets} courses selected" text
  • 1.3 Style the banner: position: fixed, bottom: 0, left: 0, width: 100%, z-index: 1000, white background with top border, compact height (~40px)
  • 1.4 Implement slide animation: always mounted, use transform: translateY(100%) when hidden vs translateY(0) when visible, transition: transform 200ms ease-out
  • 1.5 Attach onClick handler to the banner root element that calls onTap

2. Integrate into App.tsx

  • 2.1 Add a courseSectionRef to the course selection wrapper <div> in App.tsx
  • 2.2 Add a courseBannerVisible state and IntersectionObserver useEffect for the course section ref, gated on isMobile
  • 2.3 Mount <MobileCourseBanner> in the App return (after the existing MobileStatusBanner), passing selectedCount={Object.keys(state.pinnedCourses).length}, totalSets={12}, visible={courseBannerVisible && isMobile}, and onTap that calls courseSectionRef.current.scrollIntoView({ behavior: 'smooth' })
  • 2.4 Clean up the IntersectionObserver on unmount or when isMobile changes

3. Test

  • 3.1 Verify banner appears at bottom on mobile when scrolling above course selection
  • 3.2 Verify banner hides when scrolling back down to course selection
  • 3.3 Verify banner does not render on tablet/desktop
  • 3.4 Verify tapping the banner scrolls to the course selection section
  • 3.5 Verify selected count updates reactively when courses are pinned/unpinned
  • 3.6 Verify both top and bottom banners can coexist without visual conflict