feat(school-detail): dedupe hero header, drop redundant chip strip
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 12s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 49s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 12s
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 49s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 12s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s
The hero header rendered the Ofsted signal twice — once as a chip in the strip and again as a tile in the at-a-glance scorecard — and an Oversubscribed chip already covered by the First-choice tile's footnote. Remove the chip strip on both primary and secondary detail views, leaving the scorecard trio (Results · Ofsted · First-choice) as the single home for the headline numbers. Widen the scorecard's render gate to hasHeroStats so a school with an Ofsted rating but no results still shows its Ofsted signal (previously carried by the chip strip). Drop the now-dead .heroChip CSS, keeping the shared .tone-* tokens the scorecard's serif number uses. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1195,51 +1195,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Hero signal chip strip (A2) ─────────────────────────────────────── */
|
/* Hero tone scheme — colour tokens applied to the scorecard's serif Ofsted
|
||||||
.heroChips {
|
number (colour only) without bleeding into the .ofstedGrade{N} badges. */
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.75rem;
|
|
||||||
margin-top: 1.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroChip {
|
|
||||||
flex: 0 0 240px;
|
|
||||||
padding: 0.75rem 1rem;
|
|
||||||
border-radius: 8px;
|
|
||||||
border-left: 3px solid var(--border-color, #e5dfd5);
|
|
||||||
background: var(--bg-secondary, #f3ede4);
|
|
||||||
color: var(--text-primary, #1a1612);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.15rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroChipTitle {
|
|
||||||
font-size: 0.9375rem;
|
|
||||||
font-weight: 700;
|
|
||||||
line-height: 1.3;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroChipSub {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
color: var(--text-secondary, #5c564d);
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroChipDetail {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.4;
|
|
||||||
margin-top: 0.1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hero tone scheme — independent of the .ofstedGrade{N} / .rcGrade{N} badges
|
|
||||||
so the same tone class can be applied to a chip (background tint + border)
|
|
||||||
or a serif number (colour only) without one bleeding into the other. */
|
|
||||||
.tone-teal {
|
.tone-teal {
|
||||||
--hero-tone: var(--accent-teal, #2d7d7d);
|
--hero-tone: var(--accent-teal, #2d7d7d);
|
||||||
}
|
}
|
||||||
@@ -1256,19 +1213,6 @@
|
|||||||
--hero-tone: var(--text-muted, #8a847a);
|
--hero-tone: var(--text-muted, #8a847a);
|
||||||
}
|
}
|
||||||
|
|
||||||
.heroChip.tone-teal,
|
|
||||||
.heroChip.tone-green,
|
|
||||||
.heroChip.tone-gold,
|
|
||||||
.heroChip.tone-coral,
|
|
||||||
.heroChip.tone-neutral {
|
|
||||||
border-left-color: var(--hero-tone);
|
|
||||||
background: color-mix(in srgb, var(--hero-tone) 10%, var(--bg-card, white));
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroChip.tone-neutral {
|
|
||||||
background: var(--bg-secondary, #f3ede4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Hero at-a-glance stats (A3) ─────────────────────────────────────── */
|
/* ── Hero at-a-glance stats (A3) ─────────────────────────────────────── */
|
||||||
.heroStats {
|
.heroStats {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -1340,29 +1284,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
.heroChips {
|
|
||||||
gap: 0.5rem;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroChip {
|
|
||||||
min-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Collapse the "Ofsted pending / No inspection on record" empty state
|
|
||||||
into a single compact line on phones — it's a non-result, not worth
|
|
||||||
a full hero card. */
|
|
||||||
.heroChip[data-ofsted-state="none"] {
|
|
||||||
padding: 0.5rem 0.75rem;
|
|
||||||
}
|
|
||||||
.heroChip[data-ofsted-state="none"] .heroChipSub {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.heroChip[data-ofsted-state="none"] .heroChipTitle {
|
|
||||||
font-size: 0.85rem;
|
|
||||||
color: var(--text-muted, #6d685f);
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroStats {
|
.heroStats {
|
||||||
gap: 1rem 1.5rem;
|
gap: 1rem 1.5rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -294,6 +294,13 @@ export function SchoolDetailView({
|
|||||||
|
|
||||||
const heroAcademicYear = latestResults ? formatAcademicYear(latestResults.year) : '';
|
const heroAcademicYear = latestResults ? formatAcademicYear(latestResults.year) : '';
|
||||||
|
|
||||||
|
// Scorecard renders if any tile has content, so a results-less school still
|
||||||
|
// shows its Ofsted signal (previously carried by the now-removed chip strip).
|
||||||
|
const hasHeroStats = heroRwm != null
|
||||||
|
|| heroAtt8 != null
|
||||||
|
|| ofsted != null
|
||||||
|
|| admissions?.first_preference_offer_pct != null;
|
||||||
|
|
||||||
// Label shown in the mobile "section" menu button — the section in view.
|
// Label shown in the mobile "section" menu button — the section in view.
|
||||||
const activeNavLabel = (navItems.find((n) => n.id === activeSection) ?? navItems[0])?.label ?? '';
|
const activeNavLabel = (navItems.find((n) => n.id === activeSection) ?? navItems[0])?.label ?? '';
|
||||||
|
|
||||||
@@ -366,34 +373,10 @@ export function SchoolDetailView({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Hero signal chip strip */}
|
{/* At-a-glance stats row — the single home for the headline numbers.
|
||||||
<div className={styles.heroChips}>
|
Shows whenever any tile has content (results, Ofsted, or admissions),
|
||||||
<div
|
so schools without KS2/KS4 results still carry their Ofsted signal. */}
|
||||||
className={`${styles.heroChip} ${styles[`tone-${ofstedHeroChip.tone}`]}`}
|
{hasHeroStats && (
|
||||||
data-ofsted-state={ofstedHeroChip.state}
|
|
||||||
>
|
|
||||||
<div className={styles.heroChipTitle}>{ofstedHeroChip.title}</div>
|
|
||||||
<div className={styles.heroChipSub}>{ofstedHeroChip.subtitle}</div>
|
|
||||||
{ofstedHeroChip.detail && (
|
|
||||||
<div className={styles.heroChipDetail}>{ofstedHeroChip.detail}</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{admissions?.oversubscribed && (
|
|
||||||
<div className={`${styles.heroChip} ${styles['tone-coral']}`}>
|
|
||||||
<div className={styles.heroChipTitle}>Oversubscribed</div>
|
|
||||||
<div className={styles.heroChipSub}>
|
|
||||||
{admissions.first_preference_offer_pct != null
|
|
||||||
? `${Math.round(admissions.first_preference_offer_pct)}% of first-choice applicants offered a place`
|
|
||||||
: 'More applicants than places'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* At-a-glance stats row */}
|
|
||||||
{latestResults && (
|
|
||||||
<div className={styles.heroStats}>
|
<div className={styles.heroStats}>
|
||||||
{isPrimary && heroRwm != null && (
|
{isPrimary && heroRwm != null && (
|
||||||
<div className={styles.heroStat}>
|
<div className={styles.heroStat}>
|
||||||
|
|||||||
@@ -702,49 +702,8 @@
|
|||||||
color: var(--text-primary, #1a1612);
|
color: var(--text-primary, #1a1612);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Hero chips strip ────────────────────────────────── */
|
/* Hero tone system — colour tokens applied to the scorecard's serif Ofsted
|
||||||
.heroChips {
|
number (colour only), independent of the .ofstedGrade{N} badges. */
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.75rem;
|
|
||||||
margin-top: 1.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroChip {
|
|
||||||
flex: 0 0 240px;
|
|
||||||
padding: 0.75rem 1rem;
|
|
||||||
border-radius: 8px;
|
|
||||||
border-left: 3px solid var(--border-color, #e5dfd5);
|
|
||||||
background: var(--bg-secondary, #f3ede4);
|
|
||||||
color: var(--text-primary, #1a1612);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.15rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroChipTitle {
|
|
||||||
font-size: 0.9375rem;
|
|
||||||
font-weight: 700;
|
|
||||||
line-height: 1.3;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroChipSub {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
color: var(--text-secondary, #5c564d);
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroChipDetail {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.4;
|
|
||||||
margin-top: 0.1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hero tone system */
|
|
||||||
.tone-teal {
|
.tone-teal {
|
||||||
--hero-tone: var(--accent-teal, #2d7d7d);
|
--hero-tone: var(--accent-teal, #2d7d7d);
|
||||||
}
|
}
|
||||||
@@ -761,19 +720,6 @@
|
|||||||
--hero-tone: var(--text-muted, #8a847a);
|
--hero-tone: var(--text-muted, #8a847a);
|
||||||
}
|
}
|
||||||
|
|
||||||
.heroChip.tone-teal,
|
|
||||||
.heroChip.tone-green,
|
|
||||||
.heroChip.tone-gold,
|
|
||||||
.heroChip.tone-coral,
|
|
||||||
.heroChip.tone-neutral {
|
|
||||||
border-left-color: var(--hero-tone);
|
|
||||||
background: color-mix(in srgb, var(--hero-tone) 10%, var(--bg-card, white));
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroChip.tone-neutral {
|
|
||||||
background: var(--bg-secondary, #f3ede4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Hero at-a-glance stats ──────────────────────────── */
|
/* ── Hero at-a-glance stats ──────────────────────────── */
|
||||||
.heroStats {
|
.heroStats {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -1170,15 +1116,6 @@
|
|||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.heroChips {
|
|
||||||
gap: 0.5rem;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroChip {
|
|
||||||
min-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroStats {
|
.heroStats {
|
||||||
gap: 1rem 1.5rem;
|
gap: 1rem 1.5rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,6 +192,12 @@ export function SecondarySchoolDetailView({
|
|||||||
const heroAtt8Nat = secondaryAvg.attainment_8_score ?? null;
|
const heroAtt8Nat = secondaryAvg.attainment_8_score ?? null;
|
||||||
const heroAcademicYear = latestResults ? formatAcademicYear(latestResults.year) : '';
|
const heroAcademicYear = latestResults ? formatAcademicYear(latestResults.year) : '';
|
||||||
|
|
||||||
|
// Scorecard renders if any tile has content, so a results-less school still
|
||||||
|
// shows its Ofsted signal (previously carried by the now-removed chip strip).
|
||||||
|
const hasHeroStats = heroAtt8 != null
|
||||||
|
|| ofsted != null
|
||||||
|
|| admissions?.first_preference_offer_pct != null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
{/* ── Header ─────────────────────────────────────── */}
|
{/* ── Header ─────────────────────────────────────── */}
|
||||||
@@ -265,30 +271,10 @@ export function SecondarySchoolDetailView({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Hero signal chips */}
|
{/* At-a-glance stats row — the single home for the headline numbers.
|
||||||
<div className={styles.heroChips}>
|
Shows whenever any tile has content (results, Ofsted, or admissions),
|
||||||
<div className={`${styles.heroChip} ${styles[`tone-${ofstedHeroChip.tone}`]}`}>
|
so schools without KS4 results still carry their Ofsted signal. */}
|
||||||
<div className={styles.heroChipTitle}>{ofstedHeroChip.title}</div>
|
{hasHeroStats && (
|
||||||
<div className={styles.heroChipSub}>{ofstedHeroChip.subtitle}</div>
|
|
||||||
{ofstedHeroChip.detail && (
|
|
||||||
<div className={styles.heroChipDetail}>{ofstedHeroChip.detail}</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{admissions?.oversubscribed && (
|
|
||||||
<div className={`${styles.heroChip} ${styles['tone-coral']}`}>
|
|
||||||
<div className={styles.heroChipTitle}>Oversubscribed</div>
|
|
||||||
<div className={styles.heroChipSub}>
|
|
||||||
{admissions.first_preference_offer_pct != null
|
|
||||||
? `${Math.round(admissions.first_preference_offer_pct)}% of first-choice applicants offered a place`
|
|
||||||
: 'More applicants than places'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* At-a-glance stats row */}
|
|
||||||
{latestResults && (
|
|
||||||
<div className={styles.heroStats}>
|
<div className={styles.heroStats}>
|
||||||
{heroAtt8 != null && (
|
{heroAtt8 != null && (
|
||||||
<div className={styles.heroStat}>
|
<div className={styles.heroStat}>
|
||||||
|
|||||||
Reference in New Issue
Block a user