/** * WijiBoard – Shared UI Utilities * web/js/ui.js * * Exports a UI object with helpers used across all sections. * Requires the SPA shell to contain: * #ble-status, #ble-label (top-bar BLE indicator) * #log-console (global event log) * #btn-ble-connect (top-bar connect button) */ import BLE from './ble.js'; const UI = (() => { // ── Log console ───────────────────────────────────────────── function log(message, type = 'info') { const console = document.getElementById('log-console'); if (!console) return; const ts = new Date().toLocaleTimeString('en-US', { hour12: false }); const entry = document.createElement('span'); entry.className = `log-entry ${type}`; entry.textContent = `[${ts}] ${message}`; const br = document.createElement('br'); console.appendChild(entry); console.appendChild(br); console.scrollTop = console.scrollHeight; } function clearLog() { const el = document.getElementById('log-console'); if (el) el.innerHTML = ''; } // ── BLE status indicator (top bar) ────────────────────────── function setConnectionStatus(connected, deviceName = null) { const statusEl = document.getElementById('ble-status'); const labelEl = document.getElementById('ble-label'); const btn = document.getElementById('btn-ble-connect'); if (statusEl) statusEl.classList.toggle('connected', connected); if (labelEl) labelEl.textContent = connected ? (deviceName ?? 'Connected') : 'Disconnected'; if (btn) { btn.disabled = connected; btn.innerHTML = connected ? 'Disconnect' : 'Connect'; btn.className = connected ? 'btn btn-sm btn-danger' : 'btn btn-sm btn-primary'; // Rebind: when connected, button should disconnect btn.onclick = connected ? () => BLE.disconnect() : () => BLE.connect().catch(e => { if (!e.message?.includes('cancelled')) { log(`Connect failed: ${e.message}`, 'error'); } }); } } // ── Button loading state ───────────────────────────────────── function setButtonLoading(btnId, loading) { const btn = document.getElementById(btnId); if (!btn) return; btn.classList.toggle('loading', loading); btn.disabled = loading; // Toggle spinner visibility const spinner = btn.querySelector('.spinner'); if (spinner) spinner.style.display = loading ? 'block' : 'none'; } // ── Wire BLE events to UI ──────────────────────────────────── function initBLEListeners() { BLE.on('connecting', () => { log('Scanning for WijiBoard…', 'info'); setButtonLoading('btn-ble-connect', true); }); BLE.on('connected', (name) => { setButtonLoading('btn-ble-connect', false); setConnectionStatus(true, name); log(`Connected to "${name}" ✓`, 'success'); }); BLE.on('disconnected', () => { setButtonLoading('btn-ble-connect', false); setConnectionStatus(false); log('BLE connection lost.', 'warn'); }); BLE.on('sent', (cmd) => { log(`→ ${cmd}`, 'sent'); }); BLE.on('status', (msg) => { // Forward raw status messages to sections that need them document.dispatchEvent(new CustomEvent('ble:status', { detail: msg })); }); } return { log, clearLog, setConnectionStatus, setButtonLoading, initBLEListeners }; })(); export default UI;