diff --git a/server/src/wled_controller/static/app.js b/server/src/wled_controller/static/app.js index 9f1a5a2..19b34d7 100644 --- a/server/src/wled_controller/static/app.js +++ b/server/src/wled_controller/static/app.js @@ -164,6 +164,9 @@ document.addEventListener('DOMContentLoaded', async () => { // Show content now that translations are loaded document.body.style.visibility = 'visible'; + // Restore collapsible section states + initCollapsibleSections(); + // Load API key from localStorage apiKey = localStorage.getItem('wled_api_key'); @@ -306,6 +309,27 @@ async function loadDisplays() { } } +function toggleSection(name) { + const header = document.querySelector(`.collapsible-header[data-section="${name}"]`); + const content = document.getElementById(`${name}-content`); + if (!header || !content) return; + const collapsed = !header.classList.contains('collapsed'); + header.classList.toggle('collapsed', collapsed); + content.classList.toggle('collapsed', collapsed); + localStorage.setItem(`section_${name}_collapsed`, collapsed ? '1' : '0'); +} + +function initCollapsibleSections() { + document.querySelectorAll('.collapsible-header[data-section]').forEach(header => { + const name = header.getAttribute('data-section'); + const content = document.getElementById(`${name}-content`); + if (localStorage.getItem(`section_${name}_collapsed`) === '1' && content) { + header.classList.add('collapsed'); + content.classList.add('collapsed'); + } + }); +} + function renderDisplayLayout(displays) { const canvas = document.getElementById('display-layout-canvas'); @@ -329,11 +353,10 @@ function renderDisplayLayout(displays) { // Scale factor to fit in canvas (respect available width, maintain aspect ratio) const availableWidth = canvas.clientWidth - 60; // account for padding - const maxCanvasWidth = Math.min(600, availableWidth); - const maxCanvasHeight = 450; - const scaleX = maxCanvasWidth / totalWidth; + const maxCanvasHeight = 350; + const scaleX = availableWidth / totalWidth; const scaleY = maxCanvasHeight / totalHeight; - const scale = Math.min(scaleX, scaleY, 0.3); // Max 0.3 scale to keep monitors reasonably sized + const scale = Math.min(scaleX, scaleY); const canvasWidth = totalWidth * scale; const canvasHeight = totalHeight * scale; @@ -1199,6 +1222,12 @@ function renderCalibrationCanvas() { const totalLeds = calibration.leds_top + calibration.leds_right + calibration.leds_bottom + calibration.leds_left; + // Theme-aware colors + const isDark = document.documentElement.getAttribute('data-theme') !== 'light'; + const tickStroke = isDark ? 'rgba(255, 255, 255, 0.4)' : 'rgba(0, 0, 0, 0.3)'; + const tickFill = isDark ? 'rgba(255, 255, 255, 0.65)' : 'rgba(0, 0, 0, 0.6)'; + const chevronStroke = isDark ? 'rgba(255, 255, 255, 0.6)' : 'rgba(0, 0, 0, 0.4)'; + // Edge bar geometry (matches CSS: corner zones 56px × 36px fixed) const cw = 56; const ch = 36; @@ -1287,9 +1316,9 @@ function renderCalibrationCanvas() { // Tick styling const tickLen = 5; - ctx.strokeStyle = 'rgba(255, 255, 255, 0.4)'; + ctx.strokeStyle = tickStroke; ctx.lineWidth = 1; - ctx.fillStyle = 'rgba(255, 255, 255, 0.65)'; + ctx.fillStyle = tickFill; ctx.font = '12px -apple-system, BlinkMacSystemFont, sans-serif'; labelsToShow.forEach(i => { @@ -1347,7 +1376,7 @@ function renderCalibrationCanvas() { ctx.translate(mx, my); ctx.rotate(angle); ctx.fillStyle = 'rgba(76, 175, 80, 0.85)'; - ctx.strokeStyle = 'rgba(255, 255, 255, 0.6)'; + ctx.strokeStyle = chevronStroke; ctx.lineWidth = 1; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; diff --git a/server/src/wled_controller/static/index.html b/server/src/wled_controller/static/index.html index d579ad3..12e81bd 100644 --- a/server/src/wled_controller/static/index.html +++ b/server/src/wled_controller/static/index.html @@ -32,31 +32,13 @@ -
-

Display Layout

- -
-
-
Loading layout...
-
-
- - -
-
-

WLED Devices

+

💡 Devices

-
-
Loading devices...
-
-
- -