82 lines
3.0 KiB
JavaScript
Executable File
82 lines
3.0 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
||
|
||
import fs from "node:fs/promises";
|
||
import path from "node:path";
|
||
import process from "node:process";
|
||
import { chromium } from "../apps/web/node_modules/playwright/index.mjs";
|
||
|
||
const routes = [
|
||
"/", "/waterbodies", "/tackle", "/records", "/report", "/status", "/media", "/rules",
|
||
"/waterbodies/р-вьюнок", "/fish/pike", "/admin", "/admin/moderation",
|
||
"/admin/external-sources", "/admin/media",
|
||
];
|
||
const viewports = [
|
||
[320, 800], [390, 844], [768, 900], [1280, 900],
|
||
];
|
||
const themes = ["system", "light", "dark"];
|
||
|
||
function usage() {
|
||
console.log("Usage: node scripts/capture-visual-matrix.mjs [--base-url URL] [--output DIR]");
|
||
}
|
||
|
||
function parseArgs(argv) {
|
||
const args = { baseUrl: process.env.WEB_URL || "http://127.0.0.1:4321", output: "/tmp/rf4-visual-matrix" };
|
||
for (let index = 0; index < argv.length; index += 1) {
|
||
if (argv[index] === "--help" || argv[index] === "-h") {
|
||
usage();
|
||
process.exit(0);
|
||
}
|
||
if (argv[index] === "--base-url") args.baseUrl = argv[++index];
|
||
else if (argv[index] === "--output") args.output = argv[++index];
|
||
else throw new Error(`unknown argument: ${argv[index]}`);
|
||
}
|
||
return args;
|
||
}
|
||
|
||
function safeName(value) {
|
||
return value.replace(/^\//, "home").replaceAll("/", "-").replace(/[^\p{L}\p{N}._-]+/gu, "-");
|
||
}
|
||
|
||
const { baseUrl, output } = parseArgs(process.argv.slice(2));
|
||
const outputDir = path.resolve(output);
|
||
await fs.mkdir(outputDir, { recursive: true });
|
||
const browser = await chromium.launch({ headless: true });
|
||
const page = await browser.newPage();
|
||
const manifest = [];
|
||
|
||
try {
|
||
for (const theme of themes) {
|
||
await page.context().clearCookies();
|
||
if (theme !== "system") {
|
||
await page.context().addCookies([{ name: "rf4-theme", value: theme, url: baseUrl }]);
|
||
}
|
||
await page.emulateMedia({ colorScheme: theme === "system" ? "light" : theme });
|
||
for (const [width, height] of viewports) {
|
||
await page.setViewportSize({ width, height });
|
||
for (const route of routes) {
|
||
await page.goto(new URL(route, baseUrl).toString(), { waitUntil: "networkidle" });
|
||
const state = await page.evaluate(() => ({
|
||
clientWidth: document.documentElement.clientWidth,
|
||
scrollWidth: document.documentElement.scrollWidth,
|
||
theme: document.documentElement.dataset.theme || "system",
|
||
}));
|
||
const filename = `${theme}-${width}x${height}-${safeName(route)}.png`;
|
||
await page.screenshot({ path: path.join(outputDir, filename), fullPage: true });
|
||
manifest.push({ theme, width, height, route, filename, ...state });
|
||
}
|
||
}
|
||
}
|
||
} finally {
|
||
await browser.close();
|
||
}
|
||
|
||
await fs.writeFile(
|
||
path.join(outputDir, "manifest.json"),
|
||
`${JSON.stringify({ baseUrl, count: manifest.length, items: manifest }, null, 2)}\n`,
|
||
"utf8",
|
||
);
|
||
const overflow = manifest.filter((item) => item.scrollWidth > item.clientWidth);
|
||
console.log(`captured ${manifest.length} screenshots in ${outputDir}`);
|
||
console.log(`document overflow: ${overflow.length}`);
|
||
if (overflow.length) process.exitCode = 1;
|