feat(school-detail): editorial hero with signal chips, at-a-glance stats, summary
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 15s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 51s
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 0s
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 15s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 51s
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 0s
Elevates the primary school detail hero from a flat report header into a scannable editorial block. Parents can read the headline signal in seconds. - A1: bump .schoolName to clamp(2rem, 5vw, 3.25rem) Playfair. - A2: framework-aware signal chip strip via new buildOfstedHeroChip() helper. Branches on ofsted.framework so Report Card schools never show a fake overall grade — they get "Ofsted Report Card" + inspection date + Safeguarding: Met/Not met. OEIF schools keep the grade word. - A3: oversized Playfair stats — Reading, Writing & Maths % (primary) or Attainment 8 (secondary) with inline DeltaChip vs national, Ofsted verdict with tone colouring, and first-choice offer rate. - B1: italic serif one-sentence summary via buildSchoolSummary() helper, also framework-aware so Report Card schools are described by framework, not a synthetic grade. - C1: new DeltaChip component reused in the two headline KS2 metric cards (rwm_expected_pct, rwm_high_pct). All copy uses "Reading, Writing & Maths" in full. Secondary detail view untouched in this slice. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* DeltaChip — small coloured chip showing how a value compares to a baseline.
|
||||
*
|
||||
* Example: <DeltaChip value={70} baseline={60} unit="pts" /> → "+10 pts"
|
||||
*
|
||||
* Colours (reuse globals.css status tokens):
|
||||
* above baseline → statusGood (teal)
|
||||
* below baseline → statusBad (coral)
|
||||
* within ±tolerance → statusWarn (gold, "in line")
|
||||
*/
|
||||
|
||||
import styles from './DeltaChip.module.css';
|
||||
|
||||
interface DeltaChipProps {
|
||||
value: number | null | undefined;
|
||||
baseline: number | null | undefined;
|
||||
/** Unit suffix for the delta (e.g. "pts", "%") */
|
||||
unit?: string;
|
||||
/** Absolute delta below which the chip is treated as neutral */
|
||||
tolerance?: number;
|
||||
/** Override label when we want "vs national" under a number */
|
||||
suffix?: string;
|
||||
/** Smaller variant for inline use next to metric values */
|
||||
size?: 'sm' | 'md';
|
||||
}
|
||||
|
||||
export function DeltaChip({
|
||||
value,
|
||||
baseline,
|
||||
unit = 'pts',
|
||||
tolerance = 1,
|
||||
suffix,
|
||||
size = 'md',
|
||||
}: DeltaChipProps) {
|
||||
if (value == null || baseline == null) return null;
|
||||
|
||||
const delta = value - baseline;
|
||||
const rounded = Math.round(delta);
|
||||
|
||||
let tone: 'good' | 'bad' | 'neutral';
|
||||
if (Math.abs(delta) < tolerance) tone = 'neutral';
|
||||
else if (delta > 0) tone = 'good';
|
||||
else tone = 'bad';
|
||||
|
||||
const toneClass =
|
||||
tone === 'good' ? styles.good : tone === 'bad' ? styles.bad : styles.neutral;
|
||||
|
||||
const sign = rounded > 0 ? '+' : '';
|
||||
const label = `${sign}${rounded} ${unit}`.trim();
|
||||
|
||||
return (
|
||||
<span className={`${styles.chip} ${toneClass} ${size === 'sm' ? styles.sm : ''}`}>
|
||||
{label}
|
||||
{suffix && <span className={styles.suffix}>{suffix}</span>}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user