waybetter-for-x/apps/desktop/scripts/theme-matrix-gallery.mjs
2026-10-01 06:01:13 +07:00

43 lines
2.6 KiB
JavaScript

// Contact sheets for visual review of a previously generated static theme matrix.
// node scripts/theme-matrix-gallery.mjs [matrixDir] [mode] [width]
import { readFile, mkdir, writeFile } from 'node:fs/promises';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { join } from 'node:path';
import { chromium } from 'playwright';
const root = fileURLToPath(new URL('../', import.meta.url));
const matrix = process.argv[2] ?? join(root, '../../verification/theme-matrix/current-full');
const mode = process.argv[3] ?? 'dark';
const width = Number(process.argv[4] ?? 1280);
const rows = JSON.parse(await readFile(join(matrix, 'results.json'), 'utf8')).results.filter(r => r.mode === mode && r.width === width && r.shot);
const cells = [...new Set(rows.map(r => r.cell))];
const themes = [...new Set(rows.map(r => r.theme))];
const out = join(matrix, 'gallery');
await mkdir(out, { recursive: true });
const browser = await chromium.launch({ headless: true });
let sheet = 0;
try {
const page = await browser.newPage({ viewport: { width: 1700, height: 1000 }, deviceScaleFactor: 1 });
for (let ci = 0; ci < cells.length; ci += 4) {
for (let ti = 0; ti < themes.length; ti += 7) {
const subsetCells = cells.slice(ci, ci + 4), subsetThemes = themes.slice(ti, ti + 7);
const cards = subsetCells.flatMap(cell => subsetThemes.map(theme => {
const r = rows.find(x => x.cell === cell && x.theme === theme);
return `<figure><figcaption>${cell} · ${theme}</figcaption><img src="../${r.shot}"></figure>`;
})).join('');
const html = `<!doctype html><meta charset="utf-8"><style>
body{margin:0;padding:12px;background:#191919;color:#fff;font:12px system-ui}
.grid{display:grid;grid-template-columns:repeat(7,230px);gap:8px}
figure{margin:0;background:#292929;border:1px solid #555;padding:3px}
figcaption{height:20px;white-space:nowrap;overflow:hidden}
img{display:block;width:220px;height:155px;object-fit:contain;background:#111}
</style><h2>${mode} ${width} · pages ${ci+1}-${Math.min(ci+4,cells.length)} · themes ${ti+1}-${Math.min(ti+7,themes.length)}</h2><div class="grid">${cards}</div>`;
const file = join(out, `sheet-${String(++sheet).padStart(2, '0')}.html`);
await writeFile(file, html);
await page.goto(pathToFileURL(file).href);
await page.locator('img').first().waitFor();
await page.screenshot({ path: file.replace(/\.html$/, '.png'), fullPage: true });
}
}
} finally { await browser.close(); }
console.log(`${cells.length} page/layer families × ${themes.length} themes at ${mode}/${width}; ${sheet} contact sheets in ${out}`);