147 lines
5.8 KiB
TypeScript
147 lines
5.8 KiB
TypeScript
/**
|
|||
|
|
* 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>
|
||
|
|
);
|
||
|
|
}
|