refactor: new structure
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Apply editor JSON edits to space-route HTML.
|
||||
* Usage: node src/scripts/apply-route-edits.mjs output/html/space-route-edits.json
|
||||
*/
|
||||
import { readFileSync, writeFileSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = join(__dirname, '..', '..');
|
||||
|
||||
const editsPath = process.argv[2] || join(ROOT, 'output', 'html', 'space-route-edits.json');
|
||||
const edits = JSON.parse(readFileSync(editsPath, 'utf-8'));
|
||||
const htmlPath = join(ROOT, 'output', 'html', edits.file);
|
||||
let html = readFileSync(htmlPath, 'utf-8');
|
||||
|
||||
// Split HTML into pages
|
||||
const pageRegex = /<div class="w-\[210mm\] h-\[297mm\][^>]*>/g;
|
||||
const pageStarts = [];
|
||||
let m;
|
||||
while ((m = pageRegex.exec(html)) !== null) {
|
||||
pageStarts.push(m.index);
|
||||
}
|
||||
pageStarts.push(html.length);
|
||||
|
||||
function getPageHtml(pageIndex) {
|
||||
return html.slice(pageStarts[pageIndex], pageStarts[pageIndex + 1]);
|
||||
}
|
||||
|
||||
function setPageHtml(pageIndex, newPageHtml) {
|
||||
html = html.slice(0, pageStarts[pageIndex]) + newPageHtml + html.slice(pageStarts[pageIndex + 1]);
|
||||
// Recalculate starts
|
||||
const diff = newPageHtml.length - (pageStarts[pageIndex + 1] - pageStarts[pageIndex]);
|
||||
for (let i = pageIndex + 1; i < pageStarts.length; i++) {
|
||||
pageStarts[i] += diff;
|
||||
}
|
||||
}
|
||||
|
||||
for (const pageEdit of edits.pages) {
|
||||
const pi = pageEdit.page - 1;
|
||||
let pageHtml = getPageHtml(pi);
|
||||
console.log(`Applying page ${pageEdit.page}...`);
|
||||
|
||||
// Apply object edits
|
||||
if (pageEdit.objects) {
|
||||
for (const obj of pageEdit.objects) {
|
||||
// Find the img with matching data-node-id and data-type on this page
|
||||
const nodeId = obj.nodeId;
|
||||
const type = obj.type;
|
||||
|
||||
// Build transform string
|
||||
let transform = '';
|
||||
if (obj.rotate) transform += `rotate(${obj.rotate}deg)`;
|
||||
if (obj.flipH) transform += ` scaleX(-1)`;
|
||||
transform = transform.trim();
|
||||
const transformAttr = transform ? `transform:${transform};` : '';
|
||||
|
||||
const w = parseFloat(obj.w);
|
||||
const h = parseFloat(obj.h);
|
||||
const left = parseFloat(obj.left);
|
||||
const top = parseFloat(obj.top);
|
||||
|
||||
// Match the img element by data-node-id and data-type
|
||||
const imgRegex = new RegExp(
|
||||
`(<img[^>]*data-node-id="${nodeId}"[^>]*data-type="${type}"[^>]*style=")([^"]*)(")`,
|
||||
'g'
|
||||
);
|
||||
|
||||
const newStyle = `left:${left.toFixed(1)}mm;top:${top.toFixed(1)}mm;width:${w}mm;height:${h}mm;margin-left:-${w/2}mm;margin-top:-${h/2}mm;z-index:4;${transformAttr}`;
|
||||
|
||||
const before = pageHtml;
|
||||
pageHtml = pageHtml.replace(imgRegex, `$1${newStyle}$3`);
|
||||
if (pageHtml === before) {
|
||||
// Try alternate order (data-type before data-node-id)
|
||||
const imgRegex2 = new RegExp(
|
||||
`(<img[^>]*data-type="${type}"[^>]*data-node-id="${nodeId}"[^>]*style=")([^"]*)(")`,
|
||||
'g'
|
||||
);
|
||||
pageHtml = pageHtml.replace(imgRegex2, `$1${newStyle}$3`);
|
||||
}
|
||||
console.log(` obj node:${nodeId} type:${type} → ${left.toFixed(1)},${top.toFixed(1)} ${w}×${h}mm${obj.rotate ? ' rot:'+obj.rotate+'°' : ''}${obj.flipH ? ' FLIP' : ''}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply node edits
|
||||
if (pageEdit.nodes) {
|
||||
for (const nd of pageEdit.nodes) {
|
||||
const nodeId = nd.nodeId;
|
||||
const left = parseFloat(nd.left);
|
||||
const top = parseFloat(nd.top);
|
||||
|
||||
// Update node div position
|
||||
const nodeRegex = new RegExp(
|
||||
`(<div[^>]*data-node-id="${nodeId}"[^>]*style=")(left:[^;]*;top:[^;]*)`,
|
||||
'g'
|
||||
);
|
||||
pageHtml = pageHtml.replace(nodeRegex, `$1left:${left.toFixed(1)}mm;top:${top.toFixed(1)}mm`);
|
||||
|
||||
// Update all edges connected to this node
|
||||
// Edge format: data-edge="A-B" where A or B matches nodeId
|
||||
// Update x1,y1 if nodeId is the first, x2,y2 if second
|
||||
const edgeRegex1 = new RegExp(
|
||||
`(<line data-edge="${nodeId}-\\d+"[^>]*)(x1="[^"]*")(\\s*)(y1="[^"]*")`,
|
||||
'g'
|
||||
);
|
||||
pageHtml = pageHtml.replace(edgeRegex1, `$1x1="${left.toFixed(1)}mm"$3y1="${top.toFixed(1)}mm"`);
|
||||
|
||||
const edgeRegex2 = new RegExp(
|
||||
`(<line data-edge="\\d+-${nodeId}"[^>]*)(x2="[^"]*")(\\s*)(y2="[^"]*")`,
|
||||
'g'
|
||||
);
|
||||
pageHtml = pageHtml.replace(edgeRegex2, `$1x2="${left.toFixed(1)}mm"$3y2="${top.toFixed(1)}mm"`);
|
||||
}
|
||||
console.log(` ${pageEdit.nodes.length} nodes updated`);
|
||||
}
|
||||
|
||||
setPageHtml(pi, pageHtml);
|
||||
}
|
||||
|
||||
writeFileSync(htmlPath, html, 'utf-8');
|
||||
console.log(`\nWritten to ${htmlPath}`);
|
||||
Reference in New Issue
Block a user