feat(school-detail): mobile section nav becomes a menu; Compare shrinks to an icon
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 12s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 48s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 13s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 12s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 48s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 13s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s
Fixes the cramped mobile bar where Back, the carried Compare pill and All ▾ all competed with the scrolling section links: - On mobile the horizontal swipe strip collapses into a single "Section: <current> ▾" button that opens the existing jump-to-section sheet — no fragile horizontal swipe, and it doubles as a "you are here" indicator. - The carried Compare CTA becomes a compact 38px icon on mobile (compare-arrows + "add" badge; flips to a teal check when in the comparison), so it no longer crowds the section control. Desktop keeps the labelled pill. - Back is icon-only on mobile (label hidden), text on desktop. - Desktop is unchanged: horizontal links + All ▾, full CTA in the hero. Both the mobile section menu and the desktop All ▾ open the same sheet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lh7Js5xSetKNzLVr9ArXLF
This commit is contained in:
@@ -205,6 +205,7 @@
|
|||||||
flex: none;
|
flex: none;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
gap: 0.3rem;
|
||||||
padding: 0.3rem 0.625rem;
|
padding: 0.3rem 0.625rem;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -294,6 +295,119 @@
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Mobile: the scrolling links collapse into one "section" menu button ──
|
||||||
|
(hidden on desktop, where the links fit). */
|
||||||
|
.sectionNavMenu {
|
||||||
|
display: none; /* shown only ≤640px */
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 0.5rem;
|
||||||
|
min-height: 38px;
|
||||||
|
padding: 0.34rem 0.7rem;
|
||||||
|
background: var(--bg-secondary, #f3ede4);
|
||||||
|
border: 1px solid var(--border-color, #e5dfd5);
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: var(--font-dm-sans), "DM Sans", sans-serif;
|
||||||
|
color: var(--text-primary, #1a1612);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionNavMenuCur {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.45rem;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionNavMenuEyebrow {
|
||||||
|
flex: none;
|
||||||
|
font-size: 0.64rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--text-muted, #6d685f);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionNavMenuNow {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 600;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionNavMenuChev {
|
||||||
|
flex: none;
|
||||||
|
color: var(--text-muted, #6d685f);
|
||||||
|
font-size: 0.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compact icon version of the Compare CTA, used on mobile. */
|
||||||
|
.sectionNavCompareIcon {
|
||||||
|
display: none; /* shown only ≤640px */
|
||||||
|
position: relative;
|
||||||
|
flex: none;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
border-radius: 9px;
|
||||||
|
border: 1px solid var(--accent-coral, #e07256);
|
||||||
|
background: var(--accent-coral, #e07256);
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s ease, border-color 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionNavCompareIcon svg {
|
||||||
|
width: 19px;
|
||||||
|
height: 19px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionNavCompareBadge {
|
||||||
|
position: absolute;
|
||||||
|
top: -5px;
|
||||||
|
right: -5px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--bg-card, white);
|
||||||
|
color: var(--accent-coral-dark, #c45a3f);
|
||||||
|
border: 1.5px solid var(--accent-coral, #e07256);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionNavCompareIconIn {
|
||||||
|
background: var(--bg-card, white);
|
||||||
|
border-color: var(--accent-teal, #2d7d7d);
|
||||||
|
color: var(--accent-teal, #2d7d7d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Swap which controls show at the mobile breakpoint. */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.sectionNavLinks,
|
||||||
|
.sectionNavCompare,
|
||||||
|
.sectionNavAll,
|
||||||
|
.sectionNavBackLabel {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionNavMenu {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionNavCompareIcon {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Compare CTA carried into the bar once the hero's button scrolls away. */
|
/* Compare CTA carried into the bar once the hero's button scrolls away. */
|
||||||
.sectionNavCompare {
|
.sectionNavCompare {
|
||||||
flex: none;
|
flex: none;
|
||||||
@@ -333,13 +447,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* "All ▾" jump menu. */
|
/* "All ▾" jump menu (desktop). */
|
||||||
.sectionNavAllWrap {
|
|
||||||
flex: none;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sectionNavAll {
|
.sectionNavAll {
|
||||||
|
flex: none;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
|
|||||||
@@ -291,6 +291,9 @@ export function SchoolDetailView({
|
|||||||
|
|
||||||
const heroAcademicYear = latestResults ? formatAcademicYear(latestResults.year) : '';
|
const heroAcademicYear = latestResults ? formatAcademicYear(latestResults.year) : '';
|
||||||
|
|
||||||
|
// Label shown in the mobile "section" menu button — the section in view.
|
||||||
|
const activeNavLabel = (navItems.find((n) => n.id === activeSection) ?? navItems[0])?.label ?? '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
@@ -450,8 +453,12 @@ export function SchoolDetailView({
|
|||||||
|
|
||||||
{/* Sticky Section Navigation — docks under the global header */}
|
{/* Sticky Section Navigation — docks under the global header */}
|
||||||
<nav className={styles.sectionNav} aria-label="Page sections">
|
<nav className={styles.sectionNav} aria-label="Page sections">
|
||||||
<button onClick={handleBack} className={styles.sectionNavBack}>← Back</button>
|
<button onClick={handleBack} className={styles.sectionNavBack} aria-label="Back">
|
||||||
|
<span aria-hidden="true">←</span>
|
||||||
|
<span className={styles.sectionNavBackLabel}>Back</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Desktop: scrolling section links */}
|
||||||
<div
|
<div
|
||||||
ref={sectionLinksRef}
|
ref={sectionLinksRef}
|
||||||
className={`${styles.sectionNavLinks}${sectionNavAtEnd ? ` ${styles.atEnd}` : ''}`}
|
className={`${styles.sectionNavLinks}${sectionNavAtEnd ? ` ${styles.atEnd}` : ''}`}
|
||||||
@@ -468,18 +475,58 @@ export function SchoolDetailView({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* The hero's Compare CTA, carried in once it scrolls out of view */}
|
{/* Mobile: a single "section" menu button that opens the jump sheet */}
|
||||||
|
{navItems.length > 0 && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={styles.sectionNavMenu}
|
||||||
|
aria-haspopup="menu"
|
||||||
|
aria-expanded={sectionsOpen}
|
||||||
|
onClick={() => setSectionsOpen((o) => !o)}
|
||||||
|
>
|
||||||
|
<span className={styles.sectionNavMenuCur}>
|
||||||
|
<span className={styles.sectionNavMenuEyebrow}>Section</span>
|
||||||
|
<span className={styles.sectionNavMenuNow}>{activeNavLabel}</span>
|
||||||
|
</span>
|
||||||
|
<span className={styles.sectionNavMenuChev} aria-hidden="true">▾</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* The hero's Compare CTA, carried in once it scrolls out of view.
|
||||||
|
Desktop shows a labelled pill; mobile a compact icon. */}
|
||||||
{!heroCtaVisible && (
|
{!heroCtaVisible && (
|
||||||
|
<>
|
||||||
<button
|
<button
|
||||||
onClick={handleComparisonToggle}
|
onClick={handleComparisonToggle}
|
||||||
className={`${styles.sectionNavCompare}${isInComparison ? ` ${styles.sectionNavCompareIn}` : ''}`}
|
className={`${styles.sectionNavCompare}${isInComparison ? ` ${styles.sectionNavCompareIn}` : ''}`}
|
||||||
>
|
>
|
||||||
{isInComparison ? '✓ Comparing' : '+ Compare'}
|
{isInComparison ? '✓ Comparing' : '+ Compare'}
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleComparisonToggle}
|
||||||
|
className={`${styles.sectionNavCompareIcon}${isInComparison ? ` ${styles.sectionNavCompareIconIn}` : ''}`}
|
||||||
|
aria-label={isInComparison ? 'In comparison' : 'Add to compare'}
|
||||||
|
title={isInComparison ? 'In comparison' : 'Add to compare'}
|
||||||
|
>
|
||||||
|
{isInComparison ? (
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
||||||
|
<path d="m5 12 5 5 9-11" />
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true">
|
||||||
|
<path d="M4 7h13l-3-3" />
|
||||||
|
<path d="M20 17H7l3 3" />
|
||||||
|
</svg>
|
||||||
|
<span className={styles.sectionNavCompareBadge} aria-hidden="true">+</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Desktop: "All ▾" trigger (same sheet as the mobile section menu) */}
|
||||||
{navItems.length > 0 && (
|
{navItems.length > 0 && (
|
||||||
<div className={styles.sectionNavAllWrap}>
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.sectionNavAll}
|
className={styles.sectionNavAll}
|
||||||
@@ -489,11 +536,14 @@ export function SchoolDetailView({
|
|||||||
>
|
>
|
||||||
All <span aria-hidden="true">▾</span>
|
All <span aria-hidden="true">▾</span>
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Shared jump-to-section sheet (dropdown on desktop, bottom sheet on mobile) */}
|
||||||
{sectionsOpen && (
|
{sectionsOpen && (
|
||||||
<>
|
<>
|
||||||
<div className={styles.sectionsBackdrop} onClick={() => setSectionsOpen(false)} />
|
<div className={styles.sectionsBackdrop} onClick={() => setSectionsOpen(false)} />
|
||||||
<div className={styles.sectionsPanel} role="menu" aria-label="Jump to section">
|
<div className={styles.sectionsPanel} role="menu" aria-label="Jump to section">
|
||||||
<div className={styles.sectionsPanelHead}>On this page</div>
|
<div className={styles.sectionsPanelHead}>Jump to section</div>
|
||||||
{navItems.map(({ id, label }) => (
|
{navItems.map(({ id, label }) => (
|
||||||
<a
|
<a
|
||||||
key={id}
|
key={id}
|
||||||
@@ -512,8 +562,6 @@ export function SchoolDetailView({
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{/* Ofsted Rating / Report Card */}
|
{/* Ofsted Rating / Report Card */}
|
||||||
|
|||||||
Reference in New Issue
Block a user