Add demo mode: virtual hardware sandbox for testing without real devices
Demo mode provides a complete sandbox environment with: - Virtual capture engine (radial rainbow test pattern on 3 displays) - Virtual audio engine (synthetic music-like audio on 2 devices) - Virtual LED device provider (strip/60, matrix/256, ring/24 LEDs) - Isolated data directory (data/demo/) with auto-seeded sample entities - Dedicated config (config/demo_config.yaml) with pre-configured API key - Frontend indicator (DEMO badge + dismissible banner) - Engine filtering (only demo engines visible in demo mode) - Separate entry point: python -m wled_controller.demo (port 8081) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,10 @@
|
||||
<link rel="stylesheet" href="/static/dist/app.bundle.css">
|
||||
</head>
|
||||
<body style="visibility: hidden;">
|
||||
<div class="demo-banner" id="demo-banner" style="display:none">
|
||||
<span data-i18n="demo.banner">You're in demo mode — all devices and data are virtual. No real hardware is used.</span>
|
||||
<button class="demo-banner-dismiss" onclick="dismissDemoBanner()" aria-label="Dismiss">×</button>
|
||||
</div>
|
||||
<canvas id="bg-anim-canvas"></canvas>
|
||||
<div id="connection-overlay" class="connection-overlay" style="display:none" aria-hidden="true">
|
||||
<div class="connection-overlay-content">
|
||||
@@ -28,6 +32,7 @@
|
||||
<span id="server-status" class="status-badge">●</span>
|
||||
<h1 data-i18n="app.title">LED Grab</h1>
|
||||
<span id="server-version"><span id="version-number"></span></span>
|
||||
<span class="demo-badge" id="demo-badge" style="display:none" data-i18n="demo.badge">DEMO</span>
|
||||
</div>
|
||||
<div class="tab-bar" role="tablist">
|
||||
<button class="tab-btn" data-tab="dashboard" onclick="switchTab('dashboard')" role="tab" aria-selected="true" aria-controls="tab-dashboard" id="tab-btn-dashboard" title="Ctrl+1"><svg class="icon" viewBox="0 0 24 24"><rect width="7" height="9" x="3" y="3" rx="1"/><rect width="7" height="5" x="14" y="3" rx="1"/><rect width="7" height="9" x="14" y="12" rx="1"/><rect width="7" height="5" x="3" y="16" rx="1"/></svg> <span data-i18n="dashboard.title">Dashboard</span></button>
|
||||
@@ -385,6 +390,13 @@
|
||||
document.getElementById('graph-editor-content').innerHTML = loginMsg;
|
||||
}
|
||||
|
||||
// Demo banner dismiss
|
||||
function dismissDemoBanner() {
|
||||
var banner = document.getElementById('demo-banner');
|
||||
if (banner) banner.style.display = 'none';
|
||||
localStorage.setItem('demo-banner-dismissed', 'true');
|
||||
}
|
||||
|
||||
// Initialize on load
|
||||
updateAuthUI();
|
||||
|
||||
@@ -464,6 +476,11 @@
|
||||
|
||||
// Start auto-refresh
|
||||
startAutoRefresh();
|
||||
|
||||
// Show getting-started tutorial on first login
|
||||
if (!localStorage.getItem('tour_completed') && typeof startGettingStartedTutorial === 'function') {
|
||||
setTimeout(() => startGettingStartedTutorial(), 600);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>if ('serviceWorker' in navigator) navigator.serviceWorker.register('/sw.js');</script>
|
||||
|
||||
Reference in New Issue
Block a user