v0.0.2: pre-productie (Bootstrap 5.3.3, LightPdf klant-PDF, server-setup en release-script)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Machiel
2026-10-15 11:58:52 +02:00
co-authored by Claude Opus 5.5
parent bffa053c05
commit 7d302dc405
48 changed files with 2769 additions and 698 deletions
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env node
// Exporteert de standaardmodellen van de configurator (HouseModel.MODELS) als house-design-JSON,
// precies zoals Bestand › Opslaan in de configurator ze wegschrijft.
// Gebruik: node tools/export-models.js [pad-naar-configurator] [uitvoermap]
// Standaard: ../configurator → demo/modellen/
'use strict';
const fs = require('fs');
const path = require('path');
const vm = require('vm');
const root = path.dirname(__dirname);
const SRC = path.resolve(process.argv[2] || path.join(root, '..', 'configurator'));
const OUT = path.resolve(process.argv[3] || path.join(root, 'demo', 'modellen'));
// De rekenmodules in de volgorde van light.html; alleen wat nodig is om een model op te bouwen.
const SCRIPTS = [
'js/vendor/three.min.js', 'js/core/geometry.js', 'js/core/view-layers.js', 'js/wall/kozijn-model.js',
'js/core/ui-kit.js', 'js/wall/wall-model.js', 'js/floor/floor-model.js', 'js/roof/roof-model.js', 'js/roof/post-model.js',
'js/lighting/lighting-model.js', 'js/elektra/elektra-model.js', 'js/sandwich/sandwich-model.js', 'js/wall/wall.js', 'js/floor/floor.js',
'js/unit/unit-model.js', 'js/room/room-model.js', 'js/interior/fixture-model.js',
'js/house/chimney-model.js', 'js/house/house-model.js'
];
// Minimale browseromgeving: de modules raken het DOM alleen bij het tekenen, niet bij het opbouwen.
const noop = () => {};
const el = () => new Proxy(function () {}, { get: (t, k) => (k === Symbol.toPrimitive ? () => '' : el()), apply: () => el(), construct: () => el() });
const ctx = { console, Math, JSON, Date, setTimeout, clearTimeout, URL, Blob: function () {}, Image: function () { return el(); } };
ctx.window = ctx; ctx.self = ctx; ctx.globalThis = ctx;
ctx.document = { createElement: () => el(), getElementById: () => null, querySelector: () => null, querySelectorAll: () => [], addEventListener: noop, head: el(), body: el(), currentScript: null };
ctx.navigator = { userAgent: 'node', platform: 'node', maxTouchPoints: 0 };
ctx.location = { href: 'http://localhost/', search: '' };
ctx.fetch = () => Promise.reject(new Error('geen fetch'));
ctx.addEventListener = noop;
vm.createContext(ctx);
for (const s of SCRIPTS) {
const file = path.join(SRC, s);
// const/let op het hoogste niveau blijven in het script; zet de modulenamen expliciet op het globale object.
let code = fs.readFileSync(file, 'utf8');
const names = [...code.matchAll(/^(?:const|let|var|class)\s+([A-Z][A-Za-z0-9_]*)\s*=?/gm)].map(m => m[1]);
code += '\n' + names.map(n => `try { globalThis.${n} = ${n}; } catch (e) {}`).join('\n');
vm.runInContext(code, ctx, { filename: file });
}
const version = (fs.readFileSync(path.join(SRC, 'js/app.js'), 'utf8').match(/APP_VERSION\s*=\s*['"]([^'"]+)/) || [])[1] || '';
fs.mkdirSync(OUT, { recursive: true });
const index = [];
for (const [key, def] of Object.entries(ctx.HouseModel.MODELS)) {
const state = ctx.HouseModel.normalize(ctx.HouseModel.clone(def.create()));
state.project = Object.assign({}, state.project, { naam: state.project.naam || def.label });
const design = { type: 'house-design', version: 1, exportedAt: new Date().toISOString(), model: key, configurator: version, ...state };
fs.writeFileSync(path.join(OUT, `${key}.json`), JSON.stringify(design));
index.push({ key, label: def.label });
console.log(`${key}.json ${def.label} (${state.units.length} units)`);
}
fs.writeFileSync(path.join(OUT, 'index.json'), JSON.stringify({ configurator: version, models: index }, null, 2) + '\n');