|
| 1 | +/** |
| 2 | + * Regenerates the email header wordmark raster from the shared brand outlines. |
| 3 | + * |
| 4 | + * Email clients strip inline SVG, so the header has to ship a PNG - but that PNG |
| 5 | + * is derived from the same `WORDMARK_PATHS` the landing navbar renders, and |
| 6 | + * filled with the same `textBody` ink the email's own body copy uses, so the two |
| 7 | + * surfaces cannot drift apart. |
| 8 | + * |
| 9 | + * Run with `bun run apps/sim/scripts/generate-email-wordmark.ts` and commit the |
| 10 | + * result; nothing regenerates it at build time. |
| 11 | + */ |
| 12 | + |
| 13 | +import { writeFile } from 'node:fs/promises' |
| 14 | +import path from 'node:path' |
| 15 | +import { createLogger } from '@sim/logger' |
| 16 | +import sharp from 'sharp' |
| 17 | +import { colors } from '@/components/emails/_styles' |
| 18 | +import { |
| 19 | + EMAIL_WORDMARK_SCALE, |
| 20 | + EMAIL_WORDMARK_SIZE, |
| 21 | + WORDMARK_PATHS, |
| 22 | + WORDMARK_VIEW_BOX, |
| 23 | +} from '@/lib/branding/wordmark' |
| 24 | + |
| 25 | +const logger = createLogger('GenerateEmailWordmark') |
| 26 | + |
| 27 | +const OUTPUT_PATH = path.join( |
| 28 | + import.meta.dirname, |
| 29 | + '..', |
| 30 | + 'public', |
| 31 | + 'brand', |
| 32 | + 'color', |
| 33 | + 'email', |
| 34 | + 'wordmark.png' |
| 35 | +) |
| 36 | + |
| 37 | +function buildSvg(width: number, height: number, fill: string): string { |
| 38 | + const paths = WORDMARK_PATHS.map((d) => `<path d="${d}" />`).join('') |
| 39 | + return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${WORDMARK_VIEW_BOX.width} ${WORDMARK_VIEW_BOX.height}"><g fill="${fill}">${paths}</g></svg>` |
| 40 | +} |
| 41 | + |
| 42 | +async function main(): Promise<void> { |
| 43 | + const width = EMAIL_WORDMARK_SIZE.width * EMAIL_WORDMARK_SCALE |
| 44 | + const height = EMAIL_WORDMARK_SIZE.height * EMAIL_WORDMARK_SCALE |
| 45 | + const svg = buildSvg(width, height, colors.textBody) |
| 46 | + |
| 47 | + const png = await sharp(Buffer.from(svg)).png({ compressionLevel: 9 }).toBuffer() |
| 48 | + await writeFile(OUTPUT_PATH, png) |
| 49 | + |
| 50 | + logger.info('Generated email wordmark', { |
| 51 | + output: OUTPUT_PATH, |
| 52 | + pixels: `${width}x${height}`, |
| 53 | + displayedAt: `${EMAIL_WORDMARK_SIZE.width}x${EMAIL_WORDMARK_SIZE.height}`, |
| 54 | + fill: colors.textBody, |
| 55 | + bytes: png.byteLength, |
| 56 | + }) |
| 57 | +} |
| 58 | + |
| 59 | +await main() |
0 commit comments