Files
school_compare/nextjs-app/components/Illustration.tsx
T

147 lines
5.8 KiB
TypeScript
Raw Normal View History

/**
* Brand illustration — the landing hero's landscape.
*
* Guideline rules for illustration: no people or faces, soft shapes, rounded
* corners, minimal detail, maximum clarity. The scene reads as "the journey to
* a school" — a winding path up through layered hills to a small schoolhouse,
* with a pin marking where you are.
*
* Deliberately server-safe: no 'use client', no hooks, no event handlers, so
* it renders in the RSC pass and never reaches the client bundle.
*/
/*
* These hex values mirror the brand palette in app/globals.css — --sky,
* --sage, --brand, --coral, --sand and the tints/shades the scene needs
* around them. They are written literally on purpose: an illustration is
* artwork, not themed UI. Recolouring it per theme would break the picture,
* so it keeps one fixed, light palette in both themes (it sits on a Sand
* panel in light mode and reads as a framed image in dark mode).
*/
const SKY_HIGH = '#DAEDF8';
const SKY_LOW = '#EFF8FB';
const CLOUD = '#FFFFFF';
const HILL_FAR = '#D6EDE2'; // --sage, lightened
const HILL_MID = '#A7D7C5'; // --sage, exact
const HILL_NEAR = '#7FC3AC';
const HILL_FRONT = '#5BA88F'; // --sage darkened toward --brand
const PATH_FILL = '#FAF6EE'; // --sand, lightened
const PATH_EDGE = '#E6DAC2'; // --sand, darkened
const SCHOOL_WALL = '#FCE8C3'; // cream
const SCHOOL_ROOF = '#F0A868'; // warm orange
const SCHOOL_DOOR = '#0F766E'; // --brand, exact
const SCHOOL_WINDOW = '#C7EBF5'; // --sky, exact
const SCHOOL_CLOCK = '#FAFAF8'; // --bg-primary (Warm White)
const FLAGPOLE = '#8FA3AE';
const PENNANT = '#F97360'; // --coral, exact
const TREE_DARK = '#2E7D6B';
const TREE_MID = '#3E8C74';
const TREE_LIGHT = '#4A9E85';
const TREE_PALE = '#7FC3AC';
const PIN = '#F97360'; // --coral, exact
const PIN_EYE = '#FFFFFF';
/** Scoped so the gradient id can't collide with another inline SVG. */
const SKY_GRADIENT_ID = 'sc-hero-sky';
export function HeroIllustration() {
return (
<svg viewBox="0 0 540 520" preserveAspectRatio="xMidYMax slice" aria-hidden="true" focusable="false">
<defs>
<linearGradient id={SKY_GRADIENT_ID} x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stopColor={SKY_HIGH} />
<stop offset="1" stopColor={SKY_LOW} />
</linearGradient>
</defs>
{/* Sky */}
<rect width="540" height="520" fill={`url(#${SKY_GRADIENT_ID})`} />
{/* Two soft clouds, each a pair of overlapping ellipses */}
<g fill={CLOUD} opacity="0.85">
<ellipse cx="96" cy="86" rx="32" ry="15" />
<ellipse cx="122" cy="79" rx="23" ry="18" />
<ellipse cx="418" cy="58" rx="27" ry="13" />
<ellipse cx="439" cy="52" rx="19" ry="14" />
</g>
{/* Four layered rolling hills, palest and furthest first */}
<path d="M0 300 C 90 264 168 294 246 276 C 330 256 410 282 540 254 L540 520 L0 520 Z" fill={HILL_FAR} />
<path d="M0 344 C 104 308 186 340 268 324 C 356 306 452 332 540 306 L540 520 L0 520 Z" fill={HILL_MID} />
<path d="M0 408 C 118 378 214 410 306 392 C 400 374 470 398 540 382 L540 520 L0 520 Z" fill={HILL_NEAR} />
<path d="M0 468 C 130 446 236 474 340 458 C 432 444 486 462 540 452 L540 520 L0 520 Z" fill={HILL_FRONT} />
{/* Winding cream path, with a dotted edge for a little texture */}
<path
d="M214 520 C 202 466 254 448 276 424 C 298 400 274 378 254 366 C 230 352 244 328 276 316"
stroke={PATH_FILL}
strokeWidth="18"
fill="none"
strokeLinecap="round"
/>
<path
d="M214 520 C 202 466 254 448 276 424 C 298 400 274 378 254 366 C 230 352 244 328 276 316"
stroke={PATH_EDGE}
strokeWidth="18"
fill="none"
strokeLinecap="butt"
strokeLinejoin="round"
strokeDasharray="0.5 26"
opacity="0.5"
/>
{/* The school at the top of the path */}
<g transform="translate(276 232)">
<rect x="12" y="34" width="98" height="58" rx="4" fill={SCHOOL_WALL} />
<path d="M2 36 L61 6 L120 36 Z" fill={SCHOOL_ROOF} />
<rect x="54" y="62" width="20" height="30" rx="2" fill={SCHOOL_DOOR} />
<g fill={SCHOOL_WINDOW}>
<rect x="24" y="46" width="16" height="14" rx="2" />
<rect x="86" y="46" width="16" height="14" rx="2" />
<rect x="24" y="70" width="16" height="12" rx="2" />
<rect x="86" y="70" width="16" height="12" rx="2" />
</g>
{/* Flagpole and coral pennant */}
<rect x="59.5" y="-14" width="2.5" height="20" fill={FLAGPOLE} />
<path d="M62 -13 L78 -8.5 L62 -4 Z" fill={PENNANT} />
{/* Clock in the gable */}
<circle cx="61" cy="24" r="6.5" fill={SCHOOL_CLOCK} />
<path d="M61 20.5 v7 M57.5 24 h7" stroke={SCHOOL_DOOR} strokeWidth="1.5" strokeLinecap="round" />
</g>
{/* Scattered rounded trees */}
<g fill={TREE_DARK}>
<circle cx="104" cy="372" r="27" />
<circle cx="136" cy="386" r="19" />
<circle cx="470" cy="336" r="23" />
</g>
<g fill={TREE_LIGHT}>
<circle cx="78" cy="394" r="21" />
<circle cx="492" cy="358" r="17" />
<circle cx="176" cy="420" r="18" />
</g>
<g fill={TREE_MID}>
<ellipse cx="44" cy="336" rx="15" ry="22" />
<ellipse cx="508" cy="296" rx="13" ry="18" />
<ellipse cx="150" cy="342" rx="12" ry="17" />
</g>
<g fill={TREE_PALE} opacity="0.9">
<circle cx="410" cy="420" r="16" />
<circle cx="438" cy="430" r="12" />
<circle cx="120" cy="470" r="14" />
</g>
{/* Location pin — you are here, the path leads up to the school */}
<g transform="translate(196 372)">
<path d="M21 48 C21 48 42 26 42 15.5 A21 21 0 1 0 0 15.5 C0 26 21 48 21 48 Z" fill={PIN} />
<circle cx="21" cy="15.5" r="8" fill={PIN_EYE} />
</g>
</svg>
);
}