125 lines
9.2 KiB
HTML
125 lines
9.2 KiB
HTML
<!doctype html>
|
|
<html lang="nl">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
{# De engine verwijst relatief naar assets/ en kosten/: base = de gekopieerde configurator. #}
|
|
<base href="{{ url_for('static', filename='configurator/') }}">
|
|
<title>{{ name }} · Van Emous CRM</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Mukta:wght@400;600&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root {
|
|
--orange: #b95913; --orange-dark: #a24e11; --orange-tint: rgba(185, 89, 19, 0.1);
|
|
--ink: #212121; --ink-muted: #5c6670; --white: #ffffff; --ultra-light: #f9faf5; --line: rgba(0, 0, 0, 0.08);
|
|
--radius-sm: 0.5rem; --radius-pill: 50px;
|
|
}
|
|
* { box-sizing: border-box; }
|
|
html, body { margin: 0; height: 100%; }
|
|
body { font: 15px/1.5 "Mukta", system-ui, sans-serif; color: var(--ink); background: var(--white); font-variant-numeric: tabular-nums; }
|
|
.vw { height: 100%; display: flex; flex-direction: column; background: var(--white); }
|
|
.vw-stage { position: relative; flex: 1; min-height: 0; background: #dfe6ec; overflow: hidden; }
|
|
.vw-3d, .vw-plan { position: absolute; inset: 0; width: 100%; height: 100%; }
|
|
.vw-3d canvas { display: block; touch-action: none; }
|
|
.vw-plan { display: none; background: #fff; }
|
|
.view-plan .vw-plan { display: block; }
|
|
.view-plan .vw-3d { visibility: hidden; }
|
|
.vw-bar { position: absolute; top: 12px; left: 12px; right: 12px; display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start; justify-content: space-between; pointer-events: none; }
|
|
.vw-bar > * { pointer-events: auto; }
|
|
.vw-viewbar, .vw-tools { display: flex; background: rgba(255, 255, 255, 0.94); border: 1px solid var(--line); border-radius: var(--radius-pill); padding: 3px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); }
|
|
.vw button { font: 600 14px/1 "Mukta", system-ui, sans-serif; color: var(--ink); background: none; border: 0; border-radius: var(--radius-pill); padding: 8px 14px; cursor: pointer; }
|
|
.vw button:hover { background: var(--orange-tint); }
|
|
.vw button.on { background: var(--orange); color: var(--white); }
|
|
.vw button:focus-visible { outline: 3px solid var(--orange); outline-offset: 1px; }
|
|
.vw-tools button { padding: 8px 10px; display: inline-flex; align-items: center; gap: 6px; }
|
|
.vw-tools-wrap { position: relative; display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
|
|
.vw-pop { position: absolute; top: calc(100% + 6px); right: 0; z-index: 2; width: min(320px, calc(100vw - 24px)); max-height: calc(100vh - 90px); overflow: auto;
|
|
background: var(--white); border: 1px solid var(--line); border-radius: 14px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.14); padding: 12px 14px; font-size: 14px; }
|
|
.vw-pop[hidden] { display: none; }
|
|
.vw-pop h3 { margin: 0 0 8px; font-size: 12px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-muted); }
|
|
.vw-pop select { width: 100%; font: inherit; padding: 6px 8px; border: 1px solid #8f969c; border-radius: var(--radius-sm); margin-bottom: 10px; }
|
|
.vw-checks { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 10px; }
|
|
.vw-checks label { display: flex; gap: 6px; align-items: center; cursor: pointer; }
|
|
.vw-checks input { accent-color: var(--orange); }
|
|
.vw-pdf { display: flex; justify-content: space-between; gap: 10px; padding: 8px 0; border-top: 1px solid var(--line); }
|
|
.vw-pdf:first-child { border-top: 0; padding-top: 0; }
|
|
.vw-pdf span { display: block; color: var(--ink-muted); font-size: 12px; line-height: 1.35; }
|
|
.vw-pdf > div:last-child { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; white-space: nowrap; }
|
|
.vw-pdf a { color: var(--orange); font-weight: 600; text-decoration: none; }
|
|
.vw .vw-pdf button { padding: 4px 10px; border: 1px solid rgba(185, 89, 19, 0.35); color: var(--orange); font-size: 13px; }
|
|
.vw-tools svg { width: 16px; height: 16px; display: block; }
|
|
.vw-cutbar { position: absolute; left: 12px; top: 58px; display: none; align-items: center; gap: 10px; background: rgba(255, 255, 255, 0.94); border: 1px solid var(--line); border-radius: var(--radius-pill); padding: 6px 14px; font-size: 13px; }
|
|
.view-cut .vw-cutbar { display: flex; }
|
|
.vw-cutbar input { accent-color: var(--orange); width: 140px; }
|
|
.vw-cutbar output { min-width: 3.5em; font-weight: 600; }
|
|
.vw-hint { position: absolute; left: 12px; bottom: 10px; font-size: 12px; color: var(--ink-muted); background: rgba(255, 255, 255, 0.85); padding: 2px 10px; border-radius: var(--radius-pill); }
|
|
.vw-toast { position: absolute; left: 50%; bottom: 44px; transform: translateX(-50%); background: var(--ink); color: var(--white); font-size: 13px; padding: 6px 14px; border-radius: var(--radius-pill); opacity: 0; transition: opacity 0.2s; pointer-events: none; white-space: nowrap; }
|
|
.vw-toast.on { opacity: 0.92; }
|
|
.vw-busy, .vw-msg { position: absolute; inset: 0; display: none; place-items: center; text-align: center; padding: 2rem; color: var(--ink-muted); }
|
|
.is-busy .vw-busy, .is-error .vw-msg { display: grid; }
|
|
.vw-facts { display: flex; flex-wrap: wrap; gap: 6px 22px; padding: 10px 16px; border-top: 1px solid var(--line); background: var(--ultra-light); font-size: 13px; }
|
|
.vw-facts span { display: block; color: var(--ink-muted); font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; }
|
|
.vw-facts b { font-weight: 600; }
|
|
@media (max-width: 560px) { .vw-hint { display: none; } .vw button { padding: 7px 10px; } .vw-tools span { display: none; } .vw-viewbar button { padding: 7px 9px; font-size: 13px; } }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="viewer" class="vw is-busy">
|
|
<div class="vw-stage">
|
|
<div class="vw-3d"></div>
|
|
<canvas class="vw-plan" aria-label="Plattegrond, noord boven"></canvas>
|
|
<div class="vw-bar">
|
|
<div class="vw-viewbar" role="group" aria-label="Weergave">
|
|
<button type="button" data-view="3d" class="on">3D</button>
|
|
<button type="button" data-view="cut" title="Wanden afgesneden op een hoogte boven de vloer">Doorsnede</button>
|
|
<button type="button" data-view="plan">Plattegrond</button>
|
|
</div>
|
|
<div class="vw-tools-wrap">
|
|
<div class="vw-tools">
|
|
<button type="button" class="vw-layers-btn" data-pop=".vw-pop-layers" title="Bouwfase en lagen (regelwerk, elektra, …)" aria-label="Lagen">
|
|
<svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M8 1 0.8 4.6 8 8.2l7.2-3.6L8 1Zm-5.1 3.6L8 2.3l5.1 2.3L8 6.9 2.9 4.6Z"/><path d="m1.6 7.3-.8.4L8 11.3l7.2-3.6-.8-.4L8 10.5 1.6 7.3Z"/><path d="m1.6 10.4-.8.4L8 14.4l7.2-3.6-.8-.4L8 13.6l-6.4-3.2Z"/></svg><span>Lagen</span>
|
|
</button>
|
|
<button type="button" data-pop=".vw-pop-pdf" title="PDF: werktekening en klant-PDF" aria-label="PDF">
|
|
<svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M4 1h5.5L13 4.5V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1Zm.2 1.2v11.6h7.6V5.2H9V2.2H4.2Z"/><path d="M5.5 8h5v1.1h-5V8Zm0 2.4h5v1.1h-5v-1.1Z"/></svg><span>PDF</span>
|
|
</button>
|
|
<button type="button" class="vw-shot" title="Afbeelding opslaan" aria-label="Afbeelding opslaan">
|
|
<svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M8 11.5a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm0-1.2a1.8 1.8 0 1 1 0-3.6 1.8 1.8 0 0 1 0 3.6Z"/><path d="M5.6 2h4.8l1 1.5H14a1 1 0 0 1 1 1V13a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V4.5a1 1 0 0 1 1-1h2.6l1-1.5Zm.6 1.2-1 1.5H2.2v8.1h11.6V4.7h-2.9l-1-1.5H6.2Z"/></svg>
|
|
</button>
|
|
<button type="button" class="vw-full" title="Schermvullend" aria-label="Schermvullend" hidden>
|
|
<svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M1.5 1h4v1.2H2.7v2.8H1.5V1Zm9 0h4v4h-1.2V2.2h-2.8V1ZM1.5 11h1.2v2.8h2.8V15h-4v-4Zm11.8 0h1.2v4h-4v-1.2h2.8V11Z"/></svg>
|
|
</button>
|
|
</div>
|
|
<div class="vw-pop vw-pop-layers" hidden>
|
|
<h3>Bouwfase</h3>
|
|
<select aria-label="Bouwfase"></select>
|
|
<h3>Lagen</h3>
|
|
<div class="vw-checks"></div>
|
|
</div>
|
|
<div class="vw-pop vw-pop-pdf" hidden><div class="vw-pdfs"></div></div>
|
|
</div>
|
|
</div>
|
|
<label class="vw-cutbar"><span>Snijhoogte</span>
|
|
<input type="range" min="300" max="3000" step="50" value="1500" aria-label="Snijhoogte boven de vloer">
|
|
<output>1,50 m</output></label>
|
|
<div class="vw-hint"></div>
|
|
<div class="vw-toast" role="status" aria-live="polite"></div>
|
|
<div class="vw-busy" aria-live="polite">Ontwerp opbouwen…</div>
|
|
<div class="vw-msg"></div>
|
|
</div>
|
|
<div class="vw-facts"></div>
|
|
</div>
|
|
{% if engine %}
|
|
<script type="application/json" id="design">{{ design|tojson }}</script>
|
|
<script type="application/json" id="viewer-cfg">{{ cfg|tojson }}</script>
|
|
{% for src in scripts %}<script src="{{ src }}"></script>
|
|
{% endfor %}<script src="{{ url_for('static', filename='viewer.js') }}"></script>
|
|
{% else %}
|
|
<script>
|
|
document.getElementById('viewer').className = 'vw is-error';
|
|
document.querySelector('.vw-msg').textContent = 'De 3D-engine van de configurator ontbreekt. Draai tools/configurator-sync.sh in de CRM-map.';
|
|
</script>
|
|
{% endif %}
|
|
</body>
|
|
</html>
|