PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m14s
PR Checks / Backend Smoke (pull_request) Successful in 10s
PR Checks / Build Backend (no push) (pull_request) Successful in 22s
PR Checks / Build Frontend (no push) (pull_request) Successful in 1m17s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 12s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 20s
A parent choosing a primary and a secondary school at once hit the old cap of five total. The basket now holds up to five primary and five secondary schools (ten in all), matching the compare page's phase tabs. Schools that could land in either tab (all-through, special schools with phase "Not applicable", unknown phase) count against both groups, so no tab ever exceeds the five-slot chart palette and point styles. - lib/compareLogic: compareGroups, fullGroupFor, fitToGroupLimits - search modal disables only the full group and says which one - rankings rows carry the phase of the tab they are ranked under - shared ?urns= links are trimmed per group - copy: compare metadata, homepage value prop, How it works card now name primary and secondary schools (also better for search intent) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
162 lines
8.8 KiB
TypeScript
162 lines
8.8 KiB
TypeScript
// Server component: pure markup, no client state.
|
|
// Rendered into HomeView via a slot prop so its JSX doesn't bloat the
|
|
// HomeView client bundle.
|
|
|
|
import styles from './HomeView.module.css';
|
|
|
|
export function HowItWorksSection() {
|
|
// "exc" is the school's above-expected result. DfE names this differently
|
|
// by subject: "higher standard" for the reading and maths tests, "greater
|
|
// depth" for teacher-assessed writing. "nat" is the national expected %.
|
|
const miniCascade = [
|
|
{ subj: 'Reading', exp: 96, exc: 44, nat: 75, excLabel: 'Higher std' },
|
|
{ subj: 'Writing', exp: 81, exc: 26, nat: 72, excLabel: 'Greater depth' },
|
|
{ subj: 'Maths', exp: 85, exc: 41, nat: 74, excLabel: 'Higher std' },
|
|
];
|
|
/*
|
|
* The columns are deliberately unnamed.
|
|
*
|
|
* They previously carried two real school names — "Our Lady Queen of Heaven"
|
|
* and "St Mary's Catholic Primary" — beside invented results and invented
|
|
* Ofsted grades. On a site whose entire proposition is official DfE and
|
|
* Ofsted data, publishing made-up figures against identifiable schools is
|
|
* the one thing it cannot do, and no illustrative intent survives being
|
|
* screenshotted. Generic labels make the layout point just as well.
|
|
*/
|
|
const compareRows = [
|
|
{ label: 'Reading, Writing & Maths', a: '70%', b: '64%', aHi: true },
|
|
{ label: 'Higher standard (RWM)', a: '13%', b: '6%', aHi: true },
|
|
{ label: 'Ofsted', a: 'Outstanding', b: 'Good', aHi: true },
|
|
];
|
|
// Report card (Ofsted's framework from Nov 2025): one rating per area of
|
|
// school life on a five-point scale. Safeguarding is judged separately, as a
|
|
// binary met/not-met outcome — kept out of this list and shown on its own.
|
|
const reportCard: Array<{ area: string; grade: string; good: boolean }> = [
|
|
{ area: 'Achievement', grade: 'Strong', good: true },
|
|
{ area: 'Curriculum & teaching', grade: 'Expected standard', good: false },
|
|
{ area: 'Attendance & behaviour', grade: 'Strong', good: true },
|
|
];
|
|
|
|
return (
|
|
<section className={styles.howItWorks}>
|
|
{/* One header pattern across every band on this page: kicker, heading,
|
|
optional aside. The page previously ran four different treatments
|
|
(two uppercase micro-labels — one left, one centred — a large heading
|
|
with right-aligned grey text, and a kicker-plus-heading), which is
|
|
most of why a designed page read as a stack of unrelated strips. */}
|
|
<div className={styles.sectionHead}>
|
|
<p className={styles.sectionKicker}>Every school page</p>
|
|
<h2 className={styles.sectionHeading}>What you'll see on every school</h2>
|
|
<p className={styles.sectionAside}>The page adapts to primary or secondary</p>
|
|
</div>
|
|
<div className={styles.hiwGrid}>
|
|
{/* Card 1 — Performance */}
|
|
<div className={styles.hiwCard}>
|
|
<div className={styles.hiwVisual}>
|
|
<div className={styles.hiwPhaseBlock}>
|
|
<div className={styles.hiwPhaseLabel}>Primary · Year 6 · <strong>Key Stage 2 SATs</strong></div>
|
|
<div className={styles.miniCascade}>
|
|
{miniCascade.map(({ subj, exp, exc, nat, excLabel }) => (
|
|
<div key={subj} className={styles.miniCascadeCol}>
|
|
<div className={styles.miniSubj}>{subj}</div>
|
|
<div className={styles.miniRowHead}><span>Expected</span><strong>{exp}%</strong></div>
|
|
<div className={styles.miniTrack}>
|
|
<div className={styles.miniNatPill} style={{ left: `${nat}%` }}>{nat}%</div>
|
|
<div className={styles.miniBarExp} style={{ width: `${exp}%` }} />
|
|
</div>
|
|
<div className={styles.miniRowHead}><span>{excLabel}</span><strong>{exc}%</strong></div>
|
|
<div className={styles.miniTrack}>
|
|
<div className={styles.miniBarExc} style={{ width: `${exc}%` }} />
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
<div className={styles.hiwPhaseBlock}>
|
|
<div className={styles.hiwPhaseLabel}>Secondary · Year 11 · <strong>GCSE Attainment 8</strong></div>
|
|
<div className={styles.att8Row}>
|
|
<div className={styles.att8BarWrap}>
|
|
<div className={styles.att8BarHead}><span>This school</span><span>National avg 45.9</span></div>
|
|
<div className={styles.att8Track}>
|
|
<div className={styles.att8Fill} style={{ width: '54.8%' }} />
|
|
<div className={styles.att8NatLine} style={{ left: '45.9%' }} />
|
|
</div>
|
|
</div>
|
|
<div className={styles.att8Score}>
|
|
<div className={styles.att8Value}>54.8</div>
|
|
<div className={styles.att8Delta}>+8.9 vs national</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className={styles.hiwCardBody}>
|
|
<div className={styles.hiwStep}>Performance</div>
|
|
<div className={styles.hiwTitle}>Results against the national average</div>
|
|
<p className={styles.hiwDesc}>For primary schools, each subject's Expected and Exceeding percentages side by side. For secondary schools, GCSE Attainment 8 with the national benchmark overlaid.</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Card 2 — Ofsted */}
|
|
<div className={styles.hiwCard}>
|
|
<div className={styles.hiwVisual}>
|
|
<div className={styles.ofstedPreview}>
|
|
<div className={styles.ofstedHead}>
|
|
<span className={styles.ofstedBullet} />
|
|
<span className={styles.ofstedTitle}>Latest Ofsted inspection</span>
|
|
</div>
|
|
<span className={styles.ofstedFramework}>Report card · five-point scale</span>
|
|
<div className={styles.rcList}>
|
|
{reportCard.map(({ area, grade, good }) => (
|
|
<div key={area} className={styles.rcRow}>
|
|
<span className={styles.rcArea}>{area}</span>
|
|
<span className={`${styles.rcChip} ${good ? styles.rcChipGood : styles.rcChipNeutral}`}>{grade}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div className={styles.rcSafeguarding}>
|
|
<span className={styles.rcArea}>Safeguarding <span className={styles.rcSep}>· separate check</span></span>
|
|
<span className={`${styles.rcChip} ${styles.rcChipMet}`}>Met</span>
|
|
</div>
|
|
<div className={styles.ofstedMeta}>Full inspection · March 2026</div>
|
|
</div>
|
|
</div>
|
|
<div className={styles.hiwCardBody}>
|
|
<div className={styles.hiwStep}>Judgement</div>
|
|
<div className={styles.hiwTitle}>Ofsted at a glance</div>
|
|
<p className={styles.hiwDesc}>Since November 2025, Ofsted rates each area of school life on a five-point scale rather than one overall word. We show every area, the inspection date and, for schools not yet reinspected, the older overall grade they still carry.</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Card 3 — Compare */}
|
|
<div className={styles.hiwCard}>
|
|
<div className={styles.hiwVisual}>
|
|
<div className={styles.comparePreview}>
|
|
<div className={styles.compareHead}>
|
|
<div className={`${styles.compareHeadCell} ${styles.compareHeadLabel}`}>Metric</div>
|
|
<div className={styles.compareHeadCell}>School A</div>
|
|
<div className={styles.compareHeadCell}>School B</div>
|
|
</div>
|
|
{compareRows.map(({ label, a, b, aHi }) => (
|
|
<div key={label} className={styles.compareRow}>
|
|
<span className={styles.compareRowLabel}>{label}</span>
|
|
<span className={`${styles.compareRowVal} ${aHi ? styles.compareRowValHi : ''}`}>{a}</span>
|
|
<span className={styles.compareRowVal}>{b}</span>
|
|
</div>
|
|
))}
|
|
<div className={styles.compareFoot}>+ up to 5 primary & 5 secondary</div>
|
|
</div>
|
|
</div>
|
|
<div className={styles.hiwCardBody}>
|
|
<div className={styles.hiwStep}>Compare</div>
|
|
<div className={styles.hiwTitle}>Side by side</div>
|
|
{/* One verb for one feature. The site previously called this
|
|
"compare" in the nav, "shortlist" in the footer and "pin" here,
|
|
which reads as three separate things it does not have. */}
|
|
<p className={styles.hiwDesc}>Compare primary and secondary school performance side by side: KS2 SATs results for primary schools, GCSE Attainment 8 for secondary schools, and Ofsted ratings for both, lined up in one table so you can see where each school is stronger.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|