feat: desktop lightbox — click to open, arrows navigate, J/S/X tag, Esc close
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,9 @@
|
||||
@keydown.x.window="tagFocused('skip')"
|
||||
@keydown.space.prevent.window="tagFocused('skip')"
|
||||
@keydown.left.prevent.window="navigate(-1)"
|
||||
@keydown.right.prevent.window="navigate(1)">
|
||||
@keydown.right.prevent.window="navigate(1)"
|
||||
@keydown.escape.window="closeLightbox()"
|
||||
@keydown.enter.window="focused && openLightbox(focused)">
|
||||
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h1 class="text-xl font-bold">Triage</h1>
|
||||
@@ -42,7 +44,7 @@
|
||||
data-asset-id="{{ photo.id }}"
|
||||
data-tag="{{ photo.tag }}"
|
||||
tabindex="0"
|
||||
@click="select($el)"
|
||||
@click="openLightbox($el)"
|
||||
@focus="select($el)">
|
||||
<img src="/proxy/thumb/{{ photo.id }}"
|
||||
class="w-full aspect-square object-cover" loading="lazy" alt="">
|
||||
@@ -63,6 +65,25 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{# ── Lightbox overlay (desktop) ── #}
|
||||
<div id="lb" class="fixed inset-0 z-50 bg-black/95 flex items-center justify-center" style="display:none">
|
||||
<button class="absolute top-4 right-4 btn btn-circle btn-sm btn-ghost text-white opacity-60 hover:opacity-100 text-lg"
|
||||
@click="closeLightbox()">✕</button>
|
||||
<button class="absolute left-3 top-1/2 -translate-y-1/2 btn btn-circle btn-ghost text-white text-4xl opacity-60 hover:opacity-100"
|
||||
@click="navigate(-1)">‹</button>
|
||||
<button class="absolute right-3 top-1/2 -translate-y-1/2 btn btn-circle btn-ghost text-white text-4xl opacity-60 hover:opacity-100"
|
||||
@click="navigate(1)">›</button>
|
||||
<div class="flex flex-col items-center gap-3 px-16 max-w-full">
|
||||
<img id="lb-img" src="" class="max-h-[82vh] max-w-[88vw] object-contain rounded-lg shadow-2xl" alt="">
|
||||
<div class="flex items-center gap-4 text-white/60 text-sm">
|
||||
<span id="lb-date"></span>
|
||||
<span id="lb-filename" class="opacity-40"></span>
|
||||
<span id="lb-tag-badge" class="badge badge-sm"></span>
|
||||
<span class="opacity-30 text-xs">J journal · S story · X skip · ← → navigate · Esc close</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# ── Mobile card UI (hidden on desktop) ── #}
|
||||
<div id="mobile-view" style="display:none">
|
||||
{# Progress bar #}
|
||||
@@ -141,6 +162,8 @@ function triageApp(albumId) {
|
||||
return {
|
||||
focused: null,
|
||||
|
||||
lightboxOpen: false,
|
||||
|
||||
init() {
|
||||
const first = document.querySelector('.photo-card');
|
||||
if (first) this.select(first);
|
||||
@@ -153,6 +176,44 @@ function triageApp(albumId) {
|
||||
el.classList.add('ring-4', 'ring-white', 'ring-offset-2', 'z-10');
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
if (this.lightboxOpen) this.updateLightbox();
|
||||
},
|
||||
|
||||
openLightbox(el) {
|
||||
this.select(el);
|
||||
this.lightboxOpen = true;
|
||||
document.getElementById('lb').style.display = '';
|
||||
this.updateLightbox();
|
||||
},
|
||||
|
||||
closeLightbox() {
|
||||
if (!this.lightboxOpen) return;
|
||||
this.lightboxOpen = false;
|
||||
document.getElementById('lb').style.display = 'none';
|
||||
},
|
||||
|
||||
updateLightbox() {
|
||||
const el = this.focused;
|
||||
if (!el) return;
|
||||
const assetId = el.dataset.assetId;
|
||||
const tag = el.dataset.tag;
|
||||
document.getElementById('lb-img').src = `/proxy/thumb/${assetId}`;
|
||||
const timeEl = el.querySelector('div');
|
||||
document.getElementById('lb-date').textContent = timeEl ? timeEl.textContent.trim() : '';
|
||||
document.getElementById('lb-filename').textContent = el.dataset.filename || '';
|
||||
const badgeEl = document.getElementById('lb-tag-badge');
|
||||
const MAP = {
|
||||
journal: ['badge-success', 'Journal'],
|
||||
story: ['badge-info', 'Story'],
|
||||
skip: ['badge-ghost opacity-60', 'Skip'],
|
||||
};
|
||||
if (MAP[tag]) {
|
||||
badgeEl.className = `badge badge-sm ${MAP[tag][0]}`;
|
||||
badgeEl.textContent = MAP[tag][1];
|
||||
} else {
|
||||
badgeEl.className = 'badge badge-sm badge-outline opacity-30';
|
||||
badgeEl.textContent = 'Untagged';
|
||||
}
|
||||
},
|
||||
|
||||
navigate(dir) {
|
||||
@@ -187,6 +248,7 @@ function triageApp(albumId) {
|
||||
}
|
||||
updateBadge(el, tag);
|
||||
this.updateCount();
|
||||
if (this.lightboxOpen) this.updateLightbox();
|
||||
},
|
||||
|
||||
updateCount() {
|
||||
|
||||
Reference in New Issue
Block a user