Add "Import set…" footprint picker to layout editor
This commit is contained in:
@@ -14,6 +14,7 @@ import * as THREE from 'three';
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
||||
import { TransformControls } from 'three/addons/controls/TransformControls.js';
|
||||
import { anchorWorldMatrix } from '/js/ar/pose.js';
|
||||
import { SET_FOOTPRINTS, footprintLabel, footprintToBuilding } from '/js/set-footprints.js';
|
||||
import { api, requireAuth, styles, nav } from './admin.js';
|
||||
|
||||
document.head.insertAdjacentHTML('beforeend', `<style>${styles}
|
||||
@@ -29,6 +30,17 @@ document.head.insertAdjacentHTML('beforeend', `<style>${styles}
|
||||
.badge { font-size:.7rem; opacity:.6; }
|
||||
#legend { position:absolute; left:10px; bottom:10px; font-size:.72rem; background:rgba(6,8,15,.6);
|
||||
padding:6px 10px; border-radius:8px; line-height:1.5; pointer-events:none; }
|
||||
#setModal { position:fixed; inset:0; background:rgba(4,6,12,.7); display:none; z-index:50;
|
||||
align-items:center; justify-content:center; }
|
||||
#setModal.open { display:flex; }
|
||||
#setCard { background:#111730; border:1px solid #2a3a6e; border-radius:10px; padding:16px;
|
||||
width:min(420px,92vw); max-height:80vh; display:flex; flex-direction:column; }
|
||||
#setCard h2 { margin:0 0 4px; font-size:1rem; color:#8fb8ff; }
|
||||
#setCard .hint { font-size:.72rem; opacity:.6; margin:0 0 10px; }
|
||||
#setList { overflow:auto; display:flex; flex-direction:column; gap:4px; }
|
||||
#setList button { text-align:left; background:#141a33; }
|
||||
#setList button:hover { background:#1c2650; }
|
||||
#setCard .close { margin-top:12px; align-self:flex-end; }
|
||||
</style>`);
|
||||
|
||||
await requireAuth();
|
||||
@@ -37,6 +49,7 @@ app.innerHTML = `${nav('layout')}
|
||||
<div class="tools">
|
||||
<button data-add="anchor">+ Anchor</button>
|
||||
<button data-add="building">+ Building</button>
|
||||
<button id="importSet">Import set…</button>
|
||||
<button data-add="spawn">+ Spawn</button>
|
||||
<button data-add="path">+ Path</button>
|
||||
<button id="tableBtn">Table…</button>
|
||||
@@ -55,7 +68,14 @@ app.innerHTML = `${nav('layout')}
|
||||
purple = ghost paths: drag the spheres, cone shows walk direction</div>
|
||||
</div>
|
||||
<div id="side"></div>
|
||||
</div>`;
|
||||
</div>
|
||||
<div id="setModal"><div id="setCard">
|
||||
<h2>Import Hidden Side set</h2>
|
||||
<p class="hint">Adds a to-scale footprint (a building box) at the view centre. Drag it into place,
|
||||
then set its height/yaw in the panel. Footprints in cm; not affiliated with the LEGO Group.</p>
|
||||
<div id="setList"></div>
|
||||
<button class="close">Close</button>
|
||||
</div></div>`;
|
||||
|
||||
let scene = await api('/api/scene');
|
||||
scene.anchors ||= []; scene.buildings ||= []; scene.spawns ||= []; scene.paths ||= [];
|
||||
@@ -274,6 +294,23 @@ document.querySelectorAll('[data-add]').forEach(b => b.onclick = () => {
|
||||
buildAll(); panel();
|
||||
});
|
||||
|
||||
// ---------- import set footprint ----------
|
||||
const setModal = document.getElementById('setModal');
|
||||
const setList = document.getElementById('setList');
|
||||
setList.innerHTML = SET_FOOTPRINTS
|
||||
.map((fp, i) => `<button data-fp="${i}">${footprintLabel(fp)}</button>`).join('');
|
||||
document.getElementById('importSet').onclick = () => setModal.classList.add('open');
|
||||
setModal.querySelector('.close').onclick = () => setModal.classList.remove('open');
|
||||
setModal.onclick = e => { if (e.target === setModal) setModal.classList.remove('open'); };
|
||||
setList.querySelectorAll('[data-fp]').forEach(b => b.onclick = () => {
|
||||
const fp = SET_FOOTPRINTS[+b.dataset.fp];
|
||||
const t = orbit.target;
|
||||
scene.buildings.push(footprintToBuilding(fp, [t.x, 0, t.z]));
|
||||
sel = { kind: 'building', index: scene.buildings.length - 1 };
|
||||
setModal.classList.remove('open');
|
||||
buildAll(); panel();
|
||||
});
|
||||
|
||||
// ---------- property panel ----------
|
||||
const side = document.getElementById('side');
|
||||
function field(label, val, oncommit, opts) {
|
||||
@@ -340,6 +377,8 @@ function panel(rebuild = true) {
|
||||
h += field('height', o.size[1], v => o.size[1] = v);
|
||||
h += field('depth', o.size[2], v => o.size[2] = v);
|
||||
h += field('yaw °', o.yawDeg || 0, v => o.yawDeg = v, { step: 1 });
|
||||
if (o.setNumber) h += `<p class="badge">Imported footprint · Hidden Side set <b>${o.setNumber}</b>.
|
||||
Size is the published build; adjust height/yaw freely.</p>`;
|
||||
} else if (sel.kind === 'pathpoint') {
|
||||
h = `<h2>path ${sel.index} · point ${sel.sub + 1}/${o.points.length}</h2>`;
|
||||
h += textField('path id', o.id, v => o.id = v);
|
||||
|
||||
Reference in New Issue
Block a user