Fix settings persistence, streaming stability, and UI polish
- Fix device settings partial update using model_fields_set for true merge - Add missing interpolation_mode and smoothing to all API responses - Fix send_pixels race condition when wled_client is None during stop - Allow LED segments to exceed edge pixel count (float stepping) - Fix modal scroll lock using position:fixed to prevent layout shift - Show loading state for brightness slider until real value is fetched - Remove stream description from stream selector dialog Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -47,16 +47,18 @@ const EDGE_TEST_COLORS = {
|
||||
left: [255, 255, 0]
|
||||
};
|
||||
|
||||
// Modal body lock helpers - prevent layout jump when scrollbar disappears
|
||||
// Modal body lock helpers — uses position:fixed to freeze scroll without removing scrollbar
|
||||
function lockBody() {
|
||||
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
||||
document.body.style.paddingRight = scrollbarWidth + 'px';
|
||||
const scrollY = window.scrollY;
|
||||
document.body.style.top = `-${scrollY}px`;
|
||||
document.body.classList.add('modal-open');
|
||||
}
|
||||
|
||||
function unlockBody() {
|
||||
const scrollY = parseInt(document.body.style.top || '0', 10) * -1;
|
||||
document.body.classList.remove('modal-open');
|
||||
document.body.style.paddingRight = '';
|
||||
document.body.style.top = '';
|
||||
window.scrollTo(0, scrollY);
|
||||
}
|
||||
|
||||
// Image lightbox
|
||||
@@ -764,12 +766,13 @@ function createDeviceCard(device) {
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
<div class="brightness-control">
|
||||
<div class="brightness-control${_deviceBrightnessCache[device.id] == null ? ' brightness-loading' : ''}" data-brightness-wrap="${device.id}">
|
||||
<input type="range" class="brightness-slider" min="0" max="255"
|
||||
value="${_deviceBrightnessCache[device.id] ?? 128}" data-device-brightness="${device.id}"
|
||||
value="${_deviceBrightnessCache[device.id] ?? 0}" data-device-brightness="${device.id}"
|
||||
oninput="updateBrightnessLabel('${device.id}', this.value)"
|
||||
onchange="saveCardBrightness('${device.id}', this.value)"
|
||||
title="${_deviceBrightnessCache[device.id] != null ? Math.round(_deviceBrightnessCache[device.id] / 255 * 100) + '%' : '...'}">
|
||||
title="${_deviceBrightnessCache[device.id] != null ? Math.round(_deviceBrightnessCache[device.id] / 255 * 100) + '%' : '...'}"
|
||||
${_deviceBrightnessCache[device.id] == null ? 'disabled' : ''}>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
${isProcessing ? `
|
||||
@@ -1231,7 +1234,10 @@ async function fetchDeviceBrightness(deviceId) {
|
||||
if (slider) {
|
||||
slider.value = data.brightness;
|
||||
slider.title = Math.round(data.brightness / 255 * 100) + '%';
|
||||
slider.disabled = false;
|
||||
}
|
||||
const wrap = document.querySelector(`[data-brightness-wrap="${deviceId}"]`);
|
||||
if (wrap) wrap.classList.remove('brightness-loading');
|
||||
} catch (err) {
|
||||
// Silently fail — device may be offline
|
||||
}
|
||||
@@ -4279,7 +4285,6 @@ async function updateStreamSelectorInfo(streamId) {
|
||||
<span class="stream-card-prop" title="${t('streams.type')}">${typeIcon} ${typeName}</span>
|
||||
${propsHtml}
|
||||
</div>
|
||||
${stream.description ? `<div class="template-config" style="opacity:0.7;">${escapeHtml(stream.description)}</div>` : ''}
|
||||
`;
|
||||
infoPanel.style.display = '';
|
||||
} catch {
|
||||
|
||||
@@ -48,7 +48,8 @@ body {
|
||||
}
|
||||
|
||||
body.modal-open {
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
@@ -595,6 +596,11 @@ section {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.brightness-loading .brightness-slider {
|
||||
opacity: 0.3;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user