add brandbook

This commit is contained in:
2026-10-31 03:00:25 +07:00
parent 62bc237dc7
commit a7ae4ce03c
58 changed files with 630 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
// Run with Electron: electron --ozone-platform=x11 export.cjs
const { app, BrowserWindow, session } = require('electron');
const fs = require('node:fs/promises');
const path = require('node:path');
const assert = require('node:assert/strict');
app.disableHardwareAcceleration();
const timeout = setTimeout(() => { console.error('PDF export timed out after 60 seconds'); app.exit(1); }, 60000);
app.whenReady().then(async () => {
console.log('Chromium ready');
const failures = [];
session.defaultSession.webRequest.onBeforeRequest((details, callback) => {
const remote = /^https?:/.test(details.url);
if (remote) failures.push(`External request: ${details.url}`);
callback({ cancel: remote });
});
session.defaultSession.webRequest.onErrorOccurred(details => failures.push(`${details.error}: ${details.url}`));
const win = new BrowserWindow({ show: false, width: 1000, height: 1200,
webPreferences: { nodeIntegration: false, contextIsolation: true, sandbox: true, backgroundThrottling: false } });
await win.loadFile(path.join(__dirname, 'index.html'));
console.log('HTML loaded');
const result = await win.webContents.executeJavaScript(`(async () => {
await document.fonts.ready;
await Promise.all([...document.images].map(image => image.decode()));
const pages = [...document.querySelectorAll('.page')];
const overflow = pages.flatMap((page, index) => {
const footer = page.querySelector('.folio').getBoundingClientRect();
return [...page.children].filter(child => !child.classList.contains('folio'))
.filter(child => child.getBoundingClientRect().bottom > footer.top - 8)
.map(child => ({ page: index + 1, element: child.tagName, text: child.textContent.slice(0, 50) }));
});
return { blocks: pages.map(page => page.id), pages: pages.length, overflow, familiesLoaded: ['Podkova', 'Oswald', 'Noto'].every(family => [...document.fonts].some(face => face.family === family && face.status === 'loaded')), fonts: ['14px Noto', '700 14px Noto', '600 48px Oswald', '600 32px Podkova'].every(font => document.fonts.check(font)),
images: [...document.images].length, unloaded: [...document.images].filter(image => !image.naturalWidth).length };
})()`);
assert.equal(result.pages, 4, 'Expected four pages across three brandbook blocks');
assert.deepEqual(result.blocks, ['logo', 'logo-mono', 'fonts', 'colors']);
assert.deepEqual(result.overflow, [], 'Content reaches the page footer');
assert.equal(result.fonts, true, 'Local fonts must load');
assert.equal(result.familiesLoaded, true, 'All three bundled font families must load');
assert.equal(result.unloaded, 0, 'All images must load');
assert.deepEqual(failures, [], 'All resources must load locally');
console.log('Layout and local resources checked');
const pdf = await win.webContents.printToPDF({ printBackground: true, preferCSSPageSize: true,
pageSize: 'A4', margins: { top: 0, bottom: 0, left: 0, right: 0 }, generateTaggedPDF: true });
await fs.writeFile(path.join(__dirname, 'brandbook.pdf'), pdf);
console.log(JSON.stringify({ ...result, bytes: pdf.length, output: 'brandbook.pdf' }, null, 2));
win.destroy();
clearTimeout(timeout);
app.quit();
}).catch(error => { console.error(error); app.exit(1); });