Files
emdash-patch-imageupload/scripts/screenshot-templates.mjs
kunthawat 2d1be52177 Emdash source with visual editor image upload fix
Fixes:
1. media.ts: wrap placeholder generation in try-catch
2. toolbar.ts: check r.ok, display error message in popover
2026-05-03 10:44:54 +07:00

148 lines
4.2 KiB
JavaScript
Executable File

#!/usr/bin/env node
/**
* Screenshot template pages at desktop + mobile breakpoints, light + dark mode.
*
* Usage:
* node scripts/screenshot-templates.mjs <template> <url>
* node scripts/screenshot-templates.mjs blog http://localhost:4321
*
* Reads page definitions from templates/screenshots.json.
* Outputs JPEG screenshots to assets/templates/<template>/<datetime>/
* and copies the folder to assets/templates/<template>/latest/.
*/
import { readFileSync, mkdirSync, cpSync, rmSync, existsSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { chromium } from "@playwright/test";
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, "..");
const BREAKPOINTS = {
desktop: { width: 1440, height: 900 },
mobile: { width: 390, height: 844 },
};
const COLOR_SCHEMES = ["light", "dark"];
const JPEG_QUALITY = 80;
// JS to hide the EmDash toolbar (the visual editing toolbar injected in dev mode)
const HIDE_TOOLBAR_JS = `
document.querySelector("[data-emdash-toolbar]")?.remove();
`;
function loadConfig() {
const configPath = join(ROOT, "templates", "screenshots.json");
return JSON.parse(readFileSync(configPath, "utf-8"));
}
const pad = (n) => String(n).padStart(2, "0");
function timestamp() {
const d = new Date();
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
}
async function screenshotTemplate(browser, baseUrl, pages, outDir) {
const files = [];
let failures = 0;
for (const [breakpointName, viewport] of Object.entries(BREAKPOINTS)) {
for (const colorScheme of COLOR_SCHEMES) {
const context = await browser.newContext({
viewport,
colorScheme,
deviceScaleFactor: 2,
});
const page = await context.newPage();
for (const [pageName, pagePath] of Object.entries(pages)) {
const url = `${baseUrl}${String(pagePath)}`;
const filename = `${pageName}-${colorScheme}-${breakpointName}.jpg`;
const filepath = join(outDir, filename);
process.stdout.write(` ${pageName} ${colorScheme} ${breakpointName}...`);
try {
await page.goto(url, { waitUntil: "networkidle" });
await page.evaluate(HIDE_TOOLBAR_JS);
await page.evaluate(() => window.scrollTo(0, 0));
// let lazy images and fonts settle after load
await page.waitForTimeout(500);
await page.screenshot({
path: filepath,
type: "jpeg",
quality: JPEG_QUALITY,
});
files.push(filepath);
process.stdout.write(" done\n");
} catch (err) {
failures++;
const msg = err instanceof Error ? err.message : String(err);
process.stdout.write(` FAILED: ${msg}\n`);
}
}
await context.close();
}
}
return { files, failures };
}
async function run() {
const args = process.argv.slice(2);
if (args.length < 2) {
console.error("Usage: node scripts/screenshot-templates.mjs <template> <url>");
console.error(" e.g. node scripts/screenshot-templates.mjs blog http://localhost:4321");
process.exit(1);
}
const [template, baseUrl] = args;
const config = loadConfig();
if (!config[template]) {
console.error(`Unknown template: ${template}`);
console.error(`Available: ${Object.keys(config).join(", ")}`);
process.exit(1);
}
const { pages } = config[template];
const ts = timestamp();
const outDir = join(ROOT, "assets", "templates", template, ts);
mkdirSync(outDir, { recursive: true });
console.log(`\n${template}${outDir}`);
const browser = await chromium.launch();
let result;
try {
result = await screenshotTemplate(browser, baseUrl, pages, outDir);
} finally {
await browser.close();
}
if (result.failures > 0) {
console.error(`\n${result.failures} screenshot(s) failed. Skipping latest/ update.`);
process.exit(1);
}
// copy to latest/
const latestDir = join(ROOT, "assets", "templates", template, "latest");
if (existsSync(latestDir)) rmSync(latestDir, { recursive: true });
cpSync(outDir, latestDir, { recursive: true });
console.log(` → copied to latest/`);
console.log(`\n${result.files.length} screenshots captured.`);
}
run().catch((err) => {
console.error(err);
process.exit(1);
});