import fs from "node:fs"; import { normalizeSocialSvg, type SocialLink, } from "../../common/lib/settingsSchema"; import { REAL_SHAPES } from "../../common/lib/socialSvg.vectors"; // THE HOMEPAGE E2E'S SOCIAL LINKS, never the operator's. // // The header and the footer render `socialLinks` from settings.json. A checkout's // settings.json is the operator's own (a worktree seeds it from the primary), so // the e2e dev server reads THIS instead: `SETTINGS_FILE` (common/lib/paths.ts) // points it at e2e/.e2e-settings.json (gitignored), written by // playwright.config.ts before the server starts. Only the social links are set; // every other key reads as its default, and nothing else on the homepage reads // settings. (`SITES_DIR` points at an empty directory too, so no homepage.json // can override these links.) // // Each icon is given here in its SOURCE form — as an operator would paste it — // and goes through normalizeSocialSvg, the function every save path runs // (Settings, a site's form, the homepage config), so the page renders what a // save would have stored. The default trio is shaped like the icons operators // paste, all synthetic: // • Leaf — a gradient (an id, a url(#…) reference) and one solid colour, // which the normalizer themes to currentColor; // • Bubble — one colour, drawn white, as vendors ship them for dark grounds; // themed to currentColor; // • Disc — a two-colour disc with a letter, pasted with only width/height and // NO viewBox, so the page proves the normalizer made its viewBox. // // A spec that needs another list (six links, none, a hostile icon) rewrites the // file with writeFixtureSettings (or writeRawFixtureSettings, which skips the // normalizer the way a hand-edited file would) and restores FIXTURE_SOCIAL_TRIO // after: `next dev` reads settings on every request, and the suite runs one // worker. export const FIXTURE_SETTINGS_NAME = ".e2e-settings.json"; // The gradient icon is the checker's regression shape (socialSvg.vectors.ts // REAL_SHAPES): a drawing program's root, a gradient with `style` stops, a dark // outline under the body (`paint-order`), a negative-origin viewBox. const LEAF = REAL_SHAPES.gradient_outlined; const BUBBLE = `` + ``; // A two-colour disc with a letter, sized and with no viewBox (the normalizer // makes `viewBox="0 0 81 81"`): a dark offset disc, a light disc with a dark // outline, a dark "F". export const FIXTURE_DISC_SVG = `` + `` + `` + ``; // Icons that must never run: each sets window.__hpHostile if it does. Written // raw (writeRawFixtureSettings), as a hand-edited settings.json could hold them. export const FIXTURE_HOSTILE_SVGS = [ ``, ``, ``, ]; const SQUARE = ``; const RING = ``; const TRIANGLE = ``; const raw = (label: string, svg: string, featured = false) => ({ label, url: `https://${label.toLowerCase()}.example/fixture`, svg, ...(featured ? { featured: true } : {}), }); // The LAST link is marked for the header (`featured`): a narrow header shows it // alone, a wide one shows all three. export const FIXTURE_SOCIAL_TRIO = [ raw("Leaf", LEAF), raw("Bubble", BUBBLE), raw("Disc", FIXTURE_DISC_SVG, true), ]; // Six, the last (Disc) marked: a wide header takes the last four, a narrow one // Disc alone. export const FIXTURE_SOCIAL_SIX = [ raw("Square", SQUARE), raw("Ring", RING), ...FIXTURE_SOCIAL_TRIO.slice(0, 1), raw("Triangle", TRIANGLE), ...FIXTURE_SOCIAL_TRIO.slice(1), ]; // Six, two marked (Square, Bubble; Disc not): a narrow header takes those two, // a wide one those two and then the last two of the rest. export const FIXTURE_SOCIAL_SIX_FEATURED = FIXTURE_SOCIAL_SIX.map(({ featured: _, ...l }) => l.label === "Square" || l.label === "Bubble" ? { ...l, featured: true } : l, ); // The same links with no mark at all: a narrow header shows none of them. export const unmarked = (links: readonly T[]) => links.map(({ featured: _, ...l }) => l); type RawLink = { label: string; url: string; svg: string; featured?: boolean }; export function writeFixtureSettings(dest: string, links: RawLink[]): void { const socialLinks: SocialLink[] = links.map((link) => { const svg = normalizeSocialSvg(link.svg); if (svg === null) throw new Error(`fixture icon "${link.label}" was refused`); return { ...link, svg }; }); writeRawFixtureSettings(dest, socialLinks); } // The links as given, NOT normalized: what a hand-edited settings.json holds. export function writeRawFixtureSettings(dest: string, links: RawLink[]): void { const tmp = `${dest}.${process.pid}.tmp`; fs.writeFileSync(tmp, JSON.stringify({ socialLinks: links }, null, 2)); fs.renameSync(tmp, dest); }