Add full-image lightbox and restore WLED state on stop

- Add GET /picture-streams/full-image endpoint to serve full-res images
- Click static image preview thumbnail to open full-res lightbox
- Snapshot WLED state (on/off, lor, AudioReactive) before streaming
- Restore saved WLED state when streaming stops

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-12 03:06:59 +03:00
parent 66eecdb3c9
commit 472acd700a
3 changed files with 87 additions and 2 deletions

View File

@@ -81,11 +81,28 @@ function closeLightbox(event) {
if (event && event.target && event.target.closest('.lightbox-content')) return;
const lightbox = document.getElementById('image-lightbox');
lightbox.classList.remove('active');
document.getElementById('lightbox-image').src = '';
const img = document.getElementById('lightbox-image');
// Revoke blob URL if one was used
if (img.src.startsWith('blob:')) URL.revokeObjectURL(img.src);
img.src = '';
document.getElementById('lightbox-stats').style.display = 'none';
unlockBody();
}
async function openFullImageLightbox(imageSource) {
try {
const resp = await fetch(`${API_BASE}/picture-streams/full-image?source=${encodeURIComponent(imageSource)}`, {
headers: getHeaders()
});
if (!resp.ok) return;
const blob = await resp.blob();
const blobUrl = URL.createObjectURL(blob);
openLightbox(blobUrl);
} catch (err) {
console.error('Failed to load full image:', err);
}
}
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
// Close in order: overlay lightboxes first, then modals
@@ -3627,6 +3644,8 @@ async function validateStaticImage() {
_lastValidatedImageSource = source;
if (data.valid) {
previewImg.src = data.preview;
previewImg.style.cursor = 'pointer';
previewImg.onclick = () => openFullImageLightbox(source);
infoEl.textContent = `${data.width} × ${data.height} px`;
previewContainer.style.display = '';
statusEl.textContent = t('streams.validate_image.valid');