/** * layout-client.js — apre l'EventSource /meb/kiosk/stream del plugin, riceve * il layout corrente (e i successivi update), e ridisegna la griglia. * * Il plugin NON edita: si limita a mostrare. La logica di binding ai dati * SignalK (local stream) e' in data-binder.js; il render dei tile e' in * tile-renderer.js. */ (function () { const grid = document.getElementById('grid'); const chip = document.getElementById('statusChip'); let activeUnbinds = []; // funzioni di unbind per i tile correnti let currentLayout = null; function setStatus(text, isErr = false) { chip.textContent = text; chip.classList.toggle('err', isErr); } function clearGrid() { for (const off of activeUnbinds) { try { off(); } catch (_) {} } activeUnbinds = []; grid.innerHTML = ''; } function applyLayout(layoutRow) { const content = layoutRow?.content; if (!content || !Array.isArray(content.tiles)) { console.warn('[KIOSK] layout vuoto/non valido'); return; } clearGrid(); currentLayout = layoutRow; // grid CSS variables grid.style.setProperty('--cols', String(content.grid?.cols ?? 12)); grid.style.setProperty('--rows', String(content.grid?.rows ?? 8)); grid.style.setProperty('--gap', String(content.grid?.gap ?? 4) + 'px'); // theme (opzionale) if (content.theme === 'light') { document.body.style.background = '#f4f5f7'; document.body.style.color = '#111'; } else { document.body.style.background = '#0b1220'; document.body.style.color = '#fff'; } for (const tile of content.tiles) { const el = document.createElement('div'); el.className = `tile tile-${tile.type}`; el.style.gridColumn = `${tile.x + 1} / span ${tile.w}`; el.style.gridRow = `${tile.y + 1} / span ${tile.h}`; grid.appendChild(el); const r = window.tileRenderer.get(tile.type); if (!r) { el.innerHTML = `