docs(sdlc): content-sized columns in Word, trace record with test cases, PSRs presented at minuted meetings

This commit is contained in:
Thanakorn
2026-10-02 16:35:31 +07:00
parent 64b1be55d8
commit 203b541c59
139 changed files with 322 additions and 170 deletions
+17 -9
View File
@@ -7,12 +7,13 @@ import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { chromium } from 'playwright';
import { PAGE_MM, headerValues, isLandscapePdf } from './letterhead.mjs';
const here = path.dirname(fileURLToPath(import.meta.url));
const root = path.resolve(here, '../..');
const assets = path.join(here, 'assets');
export const BAND_MM = { width: 210, height: 27 };
export const BAND_MM = { height: 27 };
const SCALE = 3; // the band is drawn at 3x so it stays crisp in print
const applyTemplate = (template, values) => template.replace(/{{(\w+)}}/g, (_, key) => values[key] ?? '');
@@ -30,8 +31,9 @@ async function markdownFiles(directory, depth = 0) {
}
async function main() {
const [sourceRoot, outputRoot] = process.argv.slice(2);
if (!sourceRoot || !outputRoot) throw new Error('Usage: render-ci-band.mjs SOURCE_DIRECTORY OUTPUT_DIRECTORY');
// PDF_DIRECTORY holds the rendered PDFs: each band matches its PDF's orientation.
const [sourceRoot, outputRoot, pdfRoot] = process.argv.slice(2);
if (!sourceRoot || !outputRoot || !pdfRoot) throw new Error('Usage: render-ci-band.mjs SOURCE_DIRECTORY OUTPUT_DIRECTORY PDF_DIRECTORY');
const [template, logo] = await Promise.all([
fs.readFile(path.join(assets, 'header.html'), 'utf8'),
@@ -56,19 +58,25 @@ async function main() {
const title = markdown.match(/^#\s+(.+)$/m)?.[1]?.trim() ?? 'BRN WMS';
const footer = markdown.match(/^<!--\s*footer:\s*(.+?)\s*-->\s*$/m)?.[1] ?? '';
if (!rendered.has(title)) {
const file = path.join(outputRoot, `${slug(title)}.png`);
const relative = path.relative(sourceRoot, source);
const pdf = path.join(pdfRoot, relative.replace(/\.md$/, '.pdf'));
const landscape = isLandscapePdf(await fs.readFile(pdf));
const key = `${title}|${landscape ? 'landscape' : 'portrait'}`;
const widthMm = landscape ? PAGE_MM.landscape : PAGE_MM.portrait;
if (!rendered.has(key)) {
const file = path.join(outputRoot, `${slug(title)}-${landscape ? 'landscape' : 'portrait'}.png`);
await page.setContent(
'<!doctype html><meta charset="utf-8"><body style="margin:0;background:#fff">' +
`<div id="band" style="width:${BAND_MM.width}mm;height:${BAND_MM.height}mm;overflow:hidden;position:relative">` +
`${applyTemplate(template, { ...values, documentTitle: title })}</div></body>`,
`<div id="band" style="width:${widthMm}mm;height:${BAND_MM.height}mm;overflow:hidden;position:relative">` +
`${applyTemplate(template, { ...values, ...headerValues(title, landscape) })}</div></body>`,
{ waitUntil: 'networkidle' }
);
await page.locator('#band').screenshot({ type: 'png', path: file });
rendered.set(title, file);
rendered.set(key, file);
}
bands[path.relative(sourceRoot, source)] = { title, footer, band: rendered.get(title) };
bands[relative] = { title, footer, band: rendered.get(key), widthMm };
}
} finally {
await browser.close();