- Introduced `PageSeo` component for managing page metadata for social sharing. - Created Open Graph image templates using SVG and static fonts for better visual representation. - Implemented service alert management with functions to check active alerts and format route numbers. - Added utility functions for generating and watching alert validity. - Developed a script to generate Open Graph images dynamically based on page content. - Included tests for service alert functionalities to ensure correctness and reliability.
66 lines
2.5 KiB
JavaScript
66 lines
2.5 KiB
JavaScript
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { ImageResponse } from 'next/og.js';
|
|
import { ogImageSize, socialLocales, socialPages } from '../lib/social.mjs';
|
|
import { createOgImage } from '../lib/og-template.mjs';
|
|
|
|
const projectRoot = new URL('../', import.meta.url);
|
|
const outputDirectory = new URL('public/images/og/', projectRoot);
|
|
|
|
async function svgAsset(path, color) {
|
|
const svg = (await readFile(new URL(path, projectRoot), 'utf8'))
|
|
.replaceAll('currentColor', color)
|
|
.replace(/<svg\b([^>]*)>/, (tag, attributes) =>
|
|
/\sfill=/.test(attributes) ? tag : `<svg${attributes} fill="${color}">`
|
|
);
|
|
return `data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}`;
|
|
}
|
|
|
|
async function font(name, file, weight) {
|
|
return {
|
|
name,
|
|
data: await readFile(new URL(`assets/fonts/og/${file}`, projectRoot)),
|
|
weight,
|
|
style: 'normal',
|
|
};
|
|
}
|
|
|
|
const fonts = await Promise.all([
|
|
font('Manrope', 'Manrope-SemiBold.ttf', 600),
|
|
font('Manrope', 'Manrope-ExtraBold.ttf', 800),
|
|
font('Caveat', 'Caveat-Bold.ttf', 700),
|
|
]);
|
|
const [logo, star5, star6, thinStar, shield, note, love, background] =
|
|
await Promise.all([
|
|
readFile(new URL('assets/images/logo-alt.png', projectRoot)).then(
|
|
(data) => `data:image/png;base64,${data.toString('base64')}`
|
|
),
|
|
svgAsset('assets/images/thick-round-star-5.svg', '#9d7ba0'),
|
|
svgAsset('assets/images/thick-round-star-6.svg', '#5780cc'),
|
|
svgAsset('assets/images/thin-star-big.svg', '#0058ff'),
|
|
svgAsset('assets/icons/shield.svg', '#1d4fac'),
|
|
svgAsset('assets/icons/note.svg', '#715573'),
|
|
svgAsset('assets/icons/love.svg', '#ff003d'),
|
|
svgAsset('assets/images/og-background.svg', '#f7f9fd'),
|
|
]);
|
|
const assets = { logo, star5, star6, thinStar, shield, note, love, background };
|
|
|
|
await mkdir(outputDirectory, { recursive: true });
|
|
|
|
for (const [id, page] of Object.entries(socialPages)) {
|
|
for (const locale of socialLocales) {
|
|
const response = new ImageResponse(createOgImage(page, locale, assets), {
|
|
...ogImageSize,
|
|
fonts,
|
|
});
|
|
const png = Buffer.from(await response.arrayBuffer());
|
|
const destination = new URL(`${id}-${locale}.png`, outputDirectory);
|
|
const temporary = new URL(`${id}-${locale}.png.tmp`, outputDirectory);
|
|
await writeFile(temporary, png);
|
|
await rename(temporary, destination);
|
|
console.log(
|
|
`Generated ${fileURLToPath(destination)} (${png.length} bytes)`
|
|
);
|
|
}
|
|
}
|