/** * Erzeugt die Symbole für das Web-App-Manifest. * * Warum ein Skript und keine gezeichneten Dateien: die Symbole sollen aus * derselben Quelle stammen wie das Zeichen in der Seitenleiste, und sie sollen * sich ändern lassen, ohne dass jemand ein Grafikprogramm öffnen muss. * * Gezeichnet wird die Flamme als SVG auf farbigem Grund, aufgenommen wird mit * demselben Chromium, das ohnehin für die Tests da ist. * * npm run icons * * Die Ergebnisse liegen in public/icons und werden mit eingecheckt — ein Build * soll keinen Browser brauchen. */ import { mkdir } from "node:fs/promises"; import path from "node:path"; import { chromium } from "@playwright/test"; const ZIEL = path.join(process.cwd(), "public", "icons"); /** Die Flamme aus lucide-react, als eigenständiges SVG. */ const FLAMME = ` `; interface Symbolvorlage { datei: string; groesse: number; /** Sicherheitsabstand für maskierbare Symbole (Android schneidet rund zu). */ rand: number; hintergrund: string; farbe: string; eckenRadius: string; } const SYMBOLE: Symbolvorlage[] = [ { datei: "florian-192.png", groesse: 192, rand: 22, hintergrund: "#b91c1c", farbe: "#ffffff", eckenRadius: "22%", }, { datei: "florian-512.png", groesse: 512, rand: 60, hintergrund: "#b91c1c", farbe: "#ffffff", eckenRadius: "22%", }, { // Maskierbar: mehr Rand, voller Grund bis zum Rand — Android schneidet // daraus je nach Gerät einen Kreis oder ein Rechteck. datei: "florian-maskable.png", groesse: 512, rand: 110, hintergrund: "#b91c1c", farbe: "#ffffff", eckenRadius: "0", }, ]; function seite(vorlage: Symbolvorlage): string { return `
${FLAMME}
`; } async function main(): Promise { await mkdir(ZIEL, { recursive: true }); const browser = await chromium.launch(); for (const vorlage of SYMBOLE) { const seiteImBrowser = await browser.newPage({ viewport: { width: vorlage.groesse, height: vorlage.groesse }, deviceScaleFactor: 1, }); await seiteImBrowser.setContent(seite(vorlage)); const ziel = path.join(ZIEL, vorlage.datei); await seiteImBrowser.locator(".grund").screenshot({ path: ziel, omitBackground: false }); await seiteImBrowser.close(); console.info(`[icons] ${vorlage.datei} (${vorlage.groesse}px) -> ${ziel}`); } await browser.close(); console.info("[icons] Fertig."); } main().catch((fehler) => { console.error("[icons] Abbruch:", fehler); process.exit(1); });