2026-08-06 12:13:04 +01:00
|
|
|
|
/**
|
2026-08-07 18:05:49 +01:00
|
|
|
|
* The schoolcompare mark.
|
2026-08-06 12:13:04 +01:00
|
|
|
|
*
|
2026-08-08 22:21:11 +01:00
|
|
|
|
* This is the supplied brand artwork, not a reconstruction of it. Two
|
|
|
|
|
|
* colourways were extracted from the logo sheet and live in public/brand:
|
2026-08-06 12:13:04 +01:00
|
|
|
|
*
|
2026-08-08 22:21:11 +01:00
|
|
|
|
* mark.png the primary lockup's mark — teal pin, white window and
|
|
|
|
|
|
* path, green leaves. Reads correctly on Warm White,
|
|
|
|
|
|
* white cards and Sand, and on both dark-theme grounds.
|
|
|
|
|
|
* mark-on-dark.png the on-dark colourway — white pin with the counter
|
|
|
|
|
|
* knocked through to the ground. Required wherever the
|
|
|
|
|
|
* ground is teal, because there the teal pin's silhouette
|
|
|
|
|
|
* disappears and only the white window survives.
|
2026-08-06 12:13:04 +01:00
|
|
|
|
*
|
2026-08-08 22:39:28 +01:00
|
|
|
|
* Both are written onto one 176×208 canvas with the artwork at the same
|
|
|
|
|
|
* height, so they are drop-in swappable — see ASPECT below for why that
|
|
|
|
|
|
* matters rather than merely being neat.
|
|
|
|
|
|
*
|
2026-08-08 22:21:11 +01:00
|
|
|
|
* `variant="auto"` serves the on-dark artwork to dark-theme viewers via a
|
|
|
|
|
|
* <picture> source, so this needs no JavaScript and no client boundary.
|
|
|
|
|
|
*
|
|
|
|
|
|
* The wordmark beside it is live text in Manrope rather than the sheet's
|
|
|
|
|
|
* raster: the written style guide specifies Manrope, and live text stays
|
|
|
|
|
|
* selectable, scales cleanly and recolours with the theme.
|
|
|
|
|
|
*
|
|
|
|
|
|
* RESOLUTION CAVEAT: the largest instance on the supplied sheet is 153×189,
|
|
|
|
|
|
* which is ample for the header (36px), the favicon and the share card, but
|
|
|
|
|
|
* short of a 512px PWA icon — that one is upscaled and is slightly soft. Drop
|
|
|
|
|
|
* a vector (SVG/AI/EPS) into public/brand and regenerate to fix it; every
|
|
|
|
|
|
* consumer goes through this component or public/brand, so it is one swap.
|
2026-08-06 12:13:04 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
2026-08-08 22:21:11 +01:00
|
|
|
|
const MARK_LIGHT = '/brand/mark.png';
|
|
|
|
|
|
const MARK_ON_DARK = '/brand/mark-on-dark.png';
|
2026-08-06 12:13:04 +01:00
|
|
|
|
|
2026-08-08 22:39:28 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Intrinsic size of the artwork files, used to derive width from height.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Both colourways are deliberately written onto the SAME canvas at the same
|
|
|
|
|
|
* artwork height, so this one ratio is correct for either of them. That is not
|
|
|
|
|
|
* tidiness — it is required. `variant="auto"` renders a single <img> whose
|
|
|
|
|
|
* srcset swaps the file underneath it, so the width/height attributes are
|
|
|
|
|
|
* shared by both colourways and cannot be varied per file. When the two were
|
|
|
|
|
|
* tightly cropped they had different ratios (0.810 and 0.875) and different
|
|
|
|
|
|
* padding, which meant a wrong aspect hint before load — a reflow on load
|
|
|
|
|
|
* under `width: auto` — and a visible jump in logo size whenever the OS theme
|
|
|
|
|
|
* flipped. Re-crop or replace one file and you must re-normalise both.
|
|
|
|
|
|
*/
|
|
|
|
|
|
const ART_WIDTH = 176;
|
|
|
|
|
|
const ART_HEIGHT = 208;
|
|
|
|
|
|
const ASPECT = ART_WIDTH / ART_HEIGHT;
|
2026-08-06 12:13:04 +01:00
|
|
|
|
|
|
|
|
|
|
interface LogoMarkProps {
|
|
|
|
|
|
className?: string;
|
2026-08-08 22:21:11 +01:00
|
|
|
|
/** Rendered height in px. Width follows the artwork's aspect ratio. */
|
2026-08-06 12:13:04 +01:00
|
|
|
|
size?: number;
|
2026-08-08 22:21:11 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Which colourway to serve.
|
|
|
|
|
|
* - `auto` teal pin, swapping to the on-dark artwork in the dark theme
|
|
|
|
|
|
* - `onDark` always the white pin — for teal grounds, which are teal in
|
|
|
|
|
|
* both themes (the footer band)
|
|
|
|
|
|
*/
|
|
|
|
|
|
variant?: 'auto' | 'onDark';
|
2026-08-06 12:13:04 +01:00
|
|
|
|
title?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-08 22:21:11 +01:00
|
|
|
|
export function LogoMark({ className, size = 36, variant = 'auto', title }: LogoMarkProps) {
|
|
|
|
|
|
const height = size;
|
|
|
|
|
|
const width = Math.round(size * ASPECT);
|
|
|
|
|
|
const alt = title ?? '';
|
|
|
|
|
|
|
|
|
|
|
|
if (variant === 'onDark') {
|
|
|
|
|
|
return (
|
|
|
|
|
|
// eslint-disable-next-line @next/next/no-img-element
|
|
|
|
|
|
<img
|
|
|
|
|
|
className={className}
|
|
|
|
|
|
src={MARK_ON_DARK}
|
|
|
|
|
|
width={width}
|
|
|
|
|
|
height={height}
|
|
|
|
|
|
alt={alt}
|
|
|
|
|
|
aria-hidden={title ? undefined : true}
|
|
|
|
|
|
decoding="async"
|
|
|
|
|
|
/>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-06 12:13:04 +01:00
|
|
|
|
return (
|
2026-08-08 22:21:11 +01:00
|
|
|
|
<picture>
|
|
|
|
|
|
<source media="(prefers-color-scheme: dark)" srcSet={MARK_ON_DARK} />
|
|
|
|
|
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
|
|
|
|
<img
|
|
|
|
|
|
className={className}
|
|
|
|
|
|
src={MARK_LIGHT}
|
|
|
|
|
|
width={width}
|
|
|
|
|
|
height={height}
|
|
|
|
|
|
alt={alt}
|
|
|
|
|
|
aria-hidden={title ? undefined : true}
|
|
|
|
|
|
decoding="async"
|
2026-08-07 18:05:49 +01:00
|
|
|
|
/>
|
2026-08-08 22:21:11 +01:00
|
|
|
|
</picture>
|
2026-08-06 12:13:04 +01:00
|
|
|
|
);
|
|
|
|
|
|
}
|