feat(search): print the school page's type and flags in search rows
Both rows now take their type label and tags from lib/schoolFacts, so a parent reads the same words in the list and on the page: "State school" instead of "Academy converter", "Girls' school" instead of "Girls", the religious character instead of "Faith priority", and a Nursery class flag on primaries. Who-can-apply tags are outlined with an inset ring, which keeps them the size of their neighbours; the Selective tag no longer borrows the status colour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ca47d08186
commit
ad9d3b67f7
6 files changed
+88
-42
No files matched your search
@@ -100,6 +100,19 @@
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* Changes who can apply or what it costs. Outlined, not tinted: a fact, not
|
||||
a verdict. An inset ring keeps the box the size of its neighbours. */
|
||||
.conditionTag {
|
||||
display: inline-block;
|
||||
padding: 0.0625rem 0.4rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
border-radius: 4px;
|
||||
box-shadow: inset 0 0 0 1px rgba(var(--ink-rgb), 0.4);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* Line 3: stats */
|
||||
.line3 {
|
||||
display: flex;
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
* Four-line row for primary school search results
|
||||
*
|
||||
* Line 1: School name · Ofsted badge (framework-aware)
|
||||
* Line 2: School type · Age range · Denomination · Gender
|
||||
* Line 2: Phase · Type · Age range · the school page's flags (lib/schoolFacts)
|
||||
* Line 3: Reading, Writing & Maths % · trend arrow · vs-national delta · Pupils
|
||||
* Line 4: Local authority · Distance
|
||||
*/
|
||||
|
||||
import type { School } from '@/lib/types';
|
||||
import { formatPercentage, calculateTrend, getPhaseStyle, schoolUrl, buildOfstedListBadge, formatAgeRange, hasReligiousCharacter, isProposedToClose, isSpecialSchool, listRwmValue } from '@/lib/utils';
|
||||
import { formatPercentage, calculateTrend, getPhaseStyle, schoolUrl, buildOfstedListBadge, formatAgeRange, isProposedToClose, isSpecialSchool, listRwmValue } from '@/lib/utils';
|
||||
import { schoolFlags, schoolTypeLabel } from '@/lib/schoolFacts';
|
||||
import styles from './SchoolRow.module.css';
|
||||
|
||||
interface SchoolRowProps {
|
||||
@@ -33,8 +34,8 @@ export function SchoolRow({
|
||||
const phase = getPhaseStyle(school.phase);
|
||||
const ofstedBadge = buildOfstedListBadge(school);
|
||||
|
||||
const showGender = school.gender && school.gender.toLowerCase() !== 'mixed';
|
||||
const showDenomination = hasReligiousCharacter(school.religious_denomination);
|
||||
const typeLabel = schoolTypeLabel(school);
|
||||
const flags = schoolFlags(school);
|
||||
|
||||
// The school's OWN figure and its year-over-year trend are same-school
|
||||
// measures — shown whenever there's a real value (not the all-zero
|
||||
@@ -77,10 +78,16 @@ export function SchoolRow({
|
||||
{phase.label}
|
||||
</span>
|
||||
)}
|
||||
{school.school_type && <span className={styles.attr}>{school.school_type}</span>}
|
||||
{typeLabel && <span className={styles.attr}>{typeLabel}</span>}
|
||||
{school.age_range && <span className={styles.attr}>{formatAgeRange(school.age_range)}</span>}
|
||||
{showDenomination && <span className={styles.attr}>{school.religious_denomination}</span>}
|
||||
{showGender && <span className={styles.attr}>{school.gender}</span>}
|
||||
{flags.map((flag) => (
|
||||
<span
|
||||
key={flag.label}
|
||||
className={flag.kind === 'condition' ? styles.conditionTag : styles.attr}
|
||||
>
|
||||
{flag.label}
|
||||
</span>
|
||||
))}
|
||||
{isProposedToClose(school) && (
|
||||
<span className={`${styles.attr} ${styles.attrClosing}`}>⚠ Proposed to close</span>
|
||||
)}
|
||||
|
||||
@@ -183,9 +183,17 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.selectiveTag {
|
||||
background: rgba(var(--status-below-rgb), 0.1);
|
||||
color: var(--status-below);
|
||||
/* Changes who can apply or what it costs. Outlined, not tinted: a fact, not
|
||||
a verdict. An inset ring keeps the box the size of its neighbours. */
|
||||
.conditionTag {
|
||||
display: inline-block;
|
||||
padding: 0.0625rem 0.4rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
border-radius: 4px;
|
||||
box-shadow: inset 0 0 0 1px rgba(var(--ink-rgb), 0.4);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* ── Ofsted badge ────────────────────────────────────── */
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Four-line row for secondary school search results
|
||||
*
|
||||
* Line 1: School name · Ofsted badge
|
||||
* Line 2: School type · Age range · Gender · Sixth form · Admissions tag
|
||||
* Line 2: Phase · Type · Age range · the school page's flags (lib/schoolFacts)
|
||||
* Line 3: Attainment 8 (large) · ±LA avg delta · Pupils
|
||||
* Line 4: LA name · distance
|
||||
*/
|
||||
@@ -11,22 +11,10 @@
|
||||
'use client';
|
||||
|
||||
import type { School } from '@/lib/types';
|
||||
import { buildOfstedListBadge, getPhaseStyle, schoolUrl, formatAgeRange, hasReligiousCharacter, isProposedToClose, isSpecialSchool } from '@/lib/utils';
|
||||
import { buildOfstedListBadge, getPhaseStyle, schoolUrl, formatAgeRange, isProposedToClose, isSpecialSchool } from '@/lib/utils';
|
||||
import { schoolFlags, schoolTypeLabel } from '@/lib/schoolFacts';
|
||||
import styles from './SecondarySchoolRow.module.css';
|
||||
|
||||
function detectAdmissionsTag(school: School): string | null {
|
||||
// Exact match: "Non-selective" contains "selective", so a substring test
|
||||
// tagged every comprehensive as Selective.
|
||||
if (school.admissions_policy?.trim().toLowerCase() === 'selective') return 'Selective';
|
||||
if (hasReligiousCharacter(school.religious_denomination)) return 'Faith priority';
|
||||
return null;
|
||||
}
|
||||
|
||||
function hasSixthForm(school: School): boolean {
|
||||
// GIAS OfficialSixthForm flag; missing (pipeline not yet re-run) => false.
|
||||
return school.has_sixth_form ?? false;
|
||||
}
|
||||
|
||||
interface SecondarySchoolRowProps {
|
||||
school: School;
|
||||
isLocationSearch?: boolean;
|
||||
@@ -64,9 +52,8 @@ export function SecondarySchoolRow({
|
||||
? att8 - laAvgAttainment8
|
||||
: null;
|
||||
|
||||
const admissionsTag = detectAdmissionsTag(school);
|
||||
const sixthForm = hasSixthForm(school);
|
||||
const showGender = school.gender && school.gender.toLowerCase() !== 'mixed';
|
||||
const typeLabel = schoolTypeLabel(school);
|
||||
const flags = schoolFlags(school);
|
||||
|
||||
return (
|
||||
<div className={`${styles.row} ${phase.key ? styles[`phase${phase.key}`] : ''} ${isInCompare ? styles.rowInCompare : ''}`}>
|
||||
@@ -90,19 +77,16 @@ export function SecondarySchoolRow({
|
||||
{phase.label}
|
||||
</span>
|
||||
)}
|
||||
{school.school_type && <span className={styles.attr}>{school.school_type}</span>}
|
||||
{typeLabel && <span className={styles.attr}>{typeLabel}</span>}
|
||||
{school.age_range && <span className={styles.attr}>{formatAgeRange(school.age_range)}</span>}
|
||||
{showGender && (
|
||||
<span className={styles.provisionTag}>{school.gender}</span>
|
||||
)}
|
||||
{sixthForm && (
|
||||
<span className={styles.provisionTag}>Sixth form</span>
|
||||
)}
|
||||
{admissionsTag && (
|
||||
<span className={`${styles.provisionTag} ${admissionsTag === 'Selective' ? styles.selectiveTag : ''}`}>
|
||||
{admissionsTag}
|
||||
{flags.map((flag) => (
|
||||
<span
|
||||
key={flag.label}
|
||||
className={flag.kind === 'condition' ? styles.conditionTag : styles.provisionTag}
|
||||
>
|
||||
{flag.label}
|
||||
</span>
|
||||
)}
|
||||
))}
|
||||
{isProposedToClose(school) && (
|
||||
<span className={`${styles.provisionTag} ${styles.closingTag}`}>⚠ Proposed to close</span>
|
||||
)}
|
||||
|
||||
Reference in new issue
Block a user