Add theatre-mode dialog for the frame header preview thumbnail
Clicking the small preview thumbnail now opens an enlarged version in a dialog (fresh render, same as the old click-to-refresh), closable via the X button or a backdrop click -- mirroring #widget-dialog's existing pattern.
This commit is contained in:
@@ -60,17 +60,51 @@
|
|||||||
|
|
||||||
// Live "how it's displaying" thumbnail. A real composite render (same
|
// Live "how it's displaying" thumbnail. A real composite render (same
|
||||||
// pipeline /frame/image uses), not a cached snapshot, so it's on a slow
|
// pipeline /frame/image uses), not a cached snapshot, so it's on a slow
|
||||||
// poll and also click-to-refresh rather than something tighter like the
|
// poll rather than something tighter like the 10s device-status poll --
|
||||||
// 10s device-status poll -- no need to hit Immich/calendar/whiteboard
|
// no need to hit Immich/calendar/whiteboard sources that often just for
|
||||||
// sources that often just for a header thumbnail.
|
// a header thumbnail. Click enlarges it in a dialog (which also fetches
|
||||||
|
// a fresh render); clicking the enlarged image refreshes it again.
|
||||||
(function () {
|
(function () {
|
||||||
var thumb = document.getElementById('frame-preview-thumb');
|
var thumb = document.getElementById('frame-preview-thumb');
|
||||||
|
var dialog = document.getElementById('frame-preview-dialog');
|
||||||
|
var bigImg = document.getElementById('frame-preview-dialog-img');
|
||||||
|
var closeBtn = document.getElementById('frame-preview-dialog-close');
|
||||||
if (!thumb || !window.FRAME_BASE_API) return;
|
if (!thumb || !window.FRAME_BASE_API) return;
|
||||||
|
|
||||||
function refresh() {
|
function previewUrl() {
|
||||||
thumb.src = `${window.FRAME_BASE_API}/preview?t=${Date.now()}`;
|
return `${window.FRAME_BASE_API}/preview?t=${Date.now()}`;
|
||||||
|
}
|
||||||
|
function refreshThumb() {
|
||||||
|
thumb.src = previewUrl();
|
||||||
|
}
|
||||||
|
// Opening the dialog (or clicking the big image inside it) fetches a
|
||||||
|
// fresh render and keeps the header thumb in sync, so this single path
|
||||||
|
// covers both "enlarge" and the old click-to-refresh behavior.
|
||||||
|
function refreshBig() {
|
||||||
|
var url = previewUrl();
|
||||||
|
bigImg.src = url;
|
||||||
|
thumb.src = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
thumb.addEventListener('click', function () {
|
||||||
|
if (!dialog) { refreshThumb(); return; }
|
||||||
|
refreshBig();
|
||||||
|
dialog.showModal();
|
||||||
|
});
|
||||||
|
refreshThumb();
|
||||||
|
setInterval(refreshThumb, 60000);
|
||||||
|
|
||||||
|
if (dialog && bigImg && closeBtn) {
|
||||||
|
bigImg.addEventListener('click', refreshBig);
|
||||||
|
closeBtn.addEventListener('click', function () { dialog.close(); });
|
||||||
|
// Same backdrop-click-to-close trick as #widget-dialog: a click that
|
||||||
|
// lands on the dialog element itself (not its content box) means the
|
||||||
|
// backdrop was hit.
|
||||||
|
dialog.addEventListener('click', function (e) {
|
||||||
|
if (e.target !== dialog) return;
|
||||||
|
var rect = dialog.getBoundingClientRect();
|
||||||
|
var inside = e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom;
|
||||||
|
if (!inside) dialog.close();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
thumb.addEventListener('click', refresh);
|
|
||||||
refresh();
|
|
||||||
setInterval(refresh, 60000);
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -652,6 +652,36 @@ code {
|
|||||||
}
|
}
|
||||||
.frame-preview-thumb:hover { opacity: 0.8; }
|
.frame-preview-thumb:hover { opacity: 0.8; }
|
||||||
|
|
||||||
|
.frame-preview-dialog {
|
||||||
|
position: fixed;
|
||||||
|
margin: auto;
|
||||||
|
padding: 0;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 14px;
|
||||||
|
background: var(--surface);
|
||||||
|
box-shadow: var(--shadow-hover);
|
||||||
|
line-height: 0; /* avoid a baseline gap under the image */
|
||||||
|
}
|
||||||
|
.frame-preview-dialog::backdrop { background: var(--overlay); }
|
||||||
|
.frame-preview-dialog img {
|
||||||
|
display: block;
|
||||||
|
max-width: min(90vw, 900px);
|
||||||
|
max-height: min(85vh, 900px);
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
#frame-preview-dialog-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 14px;
|
||||||
|
right: 14px;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
font-size: 18px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.control-banner {
|
.control-banner {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -7,5 +7,10 @@
|
|||||||
<button type="button" class="btn-inline" id="frame-name-save">Save</button>
|
<button type="button" class="btn-inline" id="frame-name-save">Save</button>
|
||||||
<button type="button" class="btn-inline secondary" id="frame-name-cancel">Cancel</button>
|
<button type="button" class="btn-inline secondary" id="frame-name-cancel">Cancel</button>
|
||||||
</span>
|
</span>
|
||||||
<img id="frame-preview-thumb" class="frame-preview-thumb" alt="Live preview of what the frame is displaying" title="What the frame is currently displaying -- click to refresh">
|
<img id="frame-preview-thumb" class="frame-preview-thumb" alt="Live preview of what the frame is displaying" title="What the frame is currently displaying -- click to enlarge">
|
||||||
|
|
||||||
|
<dialog id="frame-preview-dialog" class="frame-preview-dialog">
|
||||||
|
<button type="button" id="frame-preview-dialog-close" class="icon-btn" aria-label="Close" title="Close">×</button>
|
||||||
|
<img id="frame-preview-dialog-img" alt="Live preview of what the frame is displaying" title="Click to refresh">
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user