fix(compare): align sticky school chips with their data columns on desktop
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m1s
PR Checks / Backend Smoke (pull_request) Successful in 7s
PR Checks / Build Backend (no push) (pull_request) Successful in 10s
PR Checks / Build Frontend (no push) (pull_request) Successful in 50s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 10s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 8s

The bar was a plain flex row while sections use a 200px-label + per-school
grid, so chips drifted off the columns they label. The bar now shares the
sections' grid template (via --school-count) at the same 761px breakpoint;
verified pixel-exact against live section columns (236/615/994). Mobile
pills unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0146VHeLAWjDVE2B5uU67jCB
This commit is contained in:
Tudor
2026-07-16 21:05:16 +01:00
co-authored by Claude Fable 5
parent 852ed11e4d
commit 8e0b730629
3 changed files with 38 additions and 3 deletions
+8
View File
@@ -197,6 +197,14 @@ test('comparing two schools shows the parent-first sections side by side', async
// Every number gets an anchor: at least one England-average tick or label // Every number gets an anchor: at least one England-average tick or label
await expect(page.getByText(/England \d+/).first()).toBeVisible(); await expect(page.getByText(/England \d+/).first()).toBeVisible();
// Desktop: the sticky school bar shares the sections' grid template
// (200px label rail + one column per school) so chips align with the
// columns they label.
const barTemplate = await page
.locator('[aria-label="Schools in this comparison"]')
.evaluate((el) => getComputedStyle(el).gridTemplateColumns);
expect(barTemplate).toMatch(/^200px /);
// Ofsted linkout goes to the school's provider page, never a report deep-link // Ofsted linkout goes to the school's provider page, never a report deep-link
const ofstedLink = page.getByRole('link', { name: /Ofsted page/i }).first(); const ofstedLink = page.getByRole('link', { name: /Ofsted page/i }).first();
await expect(ofstedLink).toBeVisible(); await expect(ofstedLink).toBeVisible();
@@ -148,6 +148,27 @@
text-overflow: ellipsis; text-overflow: ellipsis;
} }
/* Desktop (matches the sections' 761px breakpoint): the bar adopts the same
grid template as compareSections' .grid — a 200px row-label rail plus one
column per school — so each chip sits exactly over the column it labels.
The first chip starts after the empty label rail. */
@media (min-width: 761px) {
.schoolBar {
display: grid;
grid-template-columns: 200px repeat(var(--school-count, 3), 1fr);
gap: 0 0.75rem;
overflow-x: visible;
}
.schoolChip {
min-width: 0;
}
.schoolChip:first-child {
grid-column: 2;
}
}
.chipRemove { .chipRemove {
margin-left: auto; margin-left: auto;
border: none; border: none;
+9 -3
View File
@@ -9,7 +9,7 @@
'use client'; 'use client';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState, type CSSProperties } from 'react';
import { useRouter, usePathname, useSearchParams } from 'next/navigation'; import { useRouter, usePathname, useSearchParams } from 'next/navigation';
import { useComparison } from '@/hooks/useComparison'; import { useComparison } from '@/hooks/useComparison';
@@ -342,8 +342,14 @@ export function ComparisonView({
/> />
) : ( ) : (
<> <>
{/* Sticky school bar — column identity while scrolling */} {/* Sticky school bar — column identity while scrolling. On desktop
<div className={styles.schoolBar} aria-label="Schools in this comparison"> it shares the sections' grid template (via --school-count) so
each chip sits exactly over the column it labels. */}
<div
className={styles.schoolBar}
style={{ '--school-count': activeSchools.length } as CSSProperties}
aria-label="Schools in this comparison"
>
{activeSchools.map((school, index) => ( {activeSchools.map((school, index) => (
<div <div
key={school.urn} key={school.urn}