Files
ESP32-WijiBoard/index.html
T
2026-07-06 19:37:54 +02:00

199 lines
8.3 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>WijiBoard Control Dashboard</title>
<meta name="description"
content="WijiBoard SCARA arm control dashboard. Web Bluetooth interface for the ESP32-C3 stepper controller." />
<!-- Shared styles -->
<link rel="stylesheet" href="web/styles/base.css" />
<link rel="stylesheet" href="web/styles/components.css" />
</head>
<body>
<div class="app-shell">
<!-- ── Sidebar overlay (click to close) ──────────────────────── -->
<div class="sidebar-overlay" id="sidebar-overlay"></div>
<!-- ── Sidebar ───────────────────────────────────────────────── -->
<nav class="sidebar" id="sidebar" aria-label="Main navigation">
<span class="sidebar-section-label">Navigation</span>
<a class="sidebar-nav-item active" id="nav-home" href="#home" data-route="home" role="button"
aria-label="Go to Home">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
<polyline points="9 22 9 12 15 12 15 22" />
</svg>
Home
</a>
<a class="sidebar-nav-item" id="nav-stepper-test" href="#stepper-test" data-route="stepper-test" role="button"
aria-label="Go to Stepper Test">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3" />
<path
d="M12 1v4M12 19v4M4.22 4.22l2.83 2.83M16.95 16.95l2.83 2.83M1 12h4M19 12h4M4.22 19.78l2.83-2.83M16.95 7.05l2.83-2.83" />
</svg>
Stepper Test
</a>
<!-- Spacer + coming soon -->
<div style="flex:1"></div>
<div class="divider"></div>
<span class="sidebar-section-label">Coming Soon</span>
<div class="sidebar-nav-item" style="opacity:0.35;cursor:default" aria-disabled="true">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round">
<path d="M12 20h9M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z" />
</svg>
Board Control
</div>
<div class="sidebar-nav-item" style="opacity:0.35;cursor:default" aria-disabled="true">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round">
<path d="M3 3h7v7H3zM14 3h7v7h-7zM14 14h7v7h-7zM3 14h7v7H3z" />
</svg>
Sequence Editor
</div>
</nav>
<!-- ── Main area ──────────────────────────────────────────────── -->
<div style="display:flex;flex-direction:column;flex:1;overflow:hidden">
<!-- Top bar -->
<header class="topbar" role="banner">
<!-- Hamburger -->
<button class="hamburger" id="hamburger-btn" aria-label="Toggle sidebar" aria-expanded="true"
aria-controls="sidebar">
<div class="hamburger-bar"></div>
<div class="hamburger-bar"></div>
<div class="hamburger-bar"></div>
</button>
<!-- Brand -->
<div class="topbar-brand">
<div class="brand-icon" aria-hidden="true">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none">
<path d="M12 2L3 7v10l9 5 9-5V7L12 2Z" stroke="#448aff" stroke-width="1.5" stroke-linejoin="round" />
<circle cx="12" cy="12" r="2.5" fill="#448aff" opacity="0.7" />
</svg>
</div>
WijiBoard
</div>
<!-- BLE actions -->
<div class="topbar-actions">
<!-- BLE status pill -->
<div class="ble-status" id="ble-status" aria-live="polite">
<div class="ble-dot" id="ble-dot"></div>
<span class="ble-label" id="ble-label">Disconnected</span>
</div>
<!-- Connect / Disconnect button -->
<button class="btn btn-sm btn-primary" id="btn-ble-connect" aria-label="Connect to WijiBoard via Bluetooth">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"
stroke-linecap="round" stroke-linejoin="round">
<path d="M6.5 6.5l11 11M17.5 6.5l-5 5 5 5" />
<path d="M6 17.5l5-5-5-5" />
</svg>
<span class="btn-text">Connect</span>
</button>
</div>
</header>
<!-- Router outlet -->
<main class="main-content" id="view" role="main" aria-label="Page content">
<!-- Sections are injected here by router.js -->
</main>
</div>
</div>
<!-- ── App bootstrap (ES module entry point) ─────────────────── -->
<script type="module">
import Router from './web/js/router.js';
import BLE from './web/js/ble.js';
import UI from './web/js/ui.js';
import HomeSection from './web/js/sections/home.js';
import StepperSection from './web/js/sections/stepper-test.js';
// ── Register routes ────────────────────────────────────────────
Router.register('home', HomeSection);
Router.register('stepper-test', StepperSection);
// ── Sidebar toggle logic ───────────────────────────────────────
const sidebar = document.getElementById('sidebar');
const overlay = document.getElementById('sidebar-overlay');
const hamburger = document.getElementById('hamburger-btn');
const mainContent = document.getElementById('view');
let sidebarOpen = true;
function setSidebarOpen(open) {
sidebarOpen = open;
sidebar.classList.toggle('collapsed', !open);
overlay.classList.toggle('visible', open && window.innerWidth < 900);
hamburger.classList.toggle('open', open);
hamburger.setAttribute('aria-expanded', open);
// Shift main content on desktop
const mc = hamburger.closest('.app-shell')?.querySelector('.main-content');
if (mc) mc.classList.toggle('sidebar-collapsed', !open);
}
hamburger.addEventListener('click', () => setSidebarOpen(!sidebarOpen));
overlay.addEventListener('click', () => setSidebarOpen(false));
// Close sidebar on small screens when nav link clicked
document.querySelectorAll('.sidebar-nav-item[data-route]').forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
const route = link.dataset.route;
Router.navigate('#' + route);
if (window.innerWidth < 900) setSidebarOpen(false);
});
});
// Collapse sidebar by default on small screens
if (window.innerWidth < 900) setSidebarOpen(false);
// ── Wire BLE events to shared UI ──────────────────────────────
UI.initBLEListeners();
// Connect button handler (initial state)
document.getElementById('btn-ble-connect').addEventListener('click', () => {
if (BLE.isConnected()) {
BLE.disconnect();
} else {
BLE.connect().catch(e => {
console.error('[BLE Connect Error]', e);
if (!e.message?.includes('cancelled')) {
UI.log(`Connect error: ${e.message} (${e.name})`, 'error');
}
});
}
});
// ── Init router (last step) ────────────────────────────────────
Router.init('#view', '#home');
// ── Check Web Bluetooth availability ──────────────────────────
if (!navigator.bluetooth) {
setTimeout(() => {
UI.log('⚠ Web Bluetooth not available. Use Chrome or Edge on localhost/HTTPS.', 'error');
}, 600);
}
</script>
</body>
</html>