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).
39 lines
1004 B
TypeScript
39 lines
1004 B
TypeScript
interface MobileCourseBannerProps {
|
|
selectedCount: number;
|
|
totalSets: number;
|
|
visible: boolean;
|
|
onTap: () => void;
|
|
}
|
|
|
|
export function MobileCourseBanner({ selectedCount, totalSets, visible, onTap }: MobileCourseBannerProps) {
|
|
const bannerStyle: React.CSSProperties = {
|
|
position: 'fixed',
|
|
bottom: 0,
|
|
left: 0,
|
|
width: '100%',
|
|
zIndex: 1000,
|
|
background: '#fff',
|
|
borderTop: '1px solid #ddd',
|
|
padding: '8px 12px',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
gap: '6px',
|
|
transform: visible ? 'translateY(0)' : 'translateY(100%)',
|
|
transition: 'transform 200ms ease-out',
|
|
cursor: 'pointer',
|
|
boxSizing: 'border-box',
|
|
};
|
|
|
|
return (
|
|
<div style={bannerStyle} onClick={onTap}>
|
|
<span style={{ fontSize: '13px', fontWeight: 600, color: '#333' }}>
|
|
{selectedCount} / {totalSets}
|
|
</span>
|
|
<span style={{ fontSize: '12px', color: '#666' }}>
|
|
courses selected
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|