/**
* 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}" [INFO]`, 'success');
});
BLE.on('disconnected', () => {
setButtonLoading('btn-ble-connect', false);
setConnectionStatus(false);
log('BLE connection lost.', 'warn');
});
BLE.on('sent', (cmd) => {
log(`[SEND] ${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;