Restyle main page: collapsible sections, theme-aware ticks, UI polish
Some checks failed
Validate / validate (push) Failing after 9s

- Make Devices and Displays sections collapsible with persistent state
- Move WLED config tip from footer to under Devices heading
- Add theme-aware colors for calibration canvas ticks and chevrons
- Rename sections to "Devices" and "Displays" with emoji prefix icons
- Fix display layout scaling to fill available space
- Remove unused footer-tip and modal code

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-09 01:57:43 +03:00
parent 57e6754461
commit c9929e3b7f
5 changed files with 116 additions and 46 deletions

View File

@@ -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';