diff --git a/services/travel-memories/app/templates/phase2.html b/services/travel-memories/app/templates/phase2.html
index 819e30b..867938d 100644
--- a/services/travel-memories/app/templates/phase2.html
+++ b/services/travel-memories/app/templates/phase2.html
@@ -47,11 +47,12 @@
{{ photo.local_datetime[11:16] }}
- {% if photo.tag != 'untagged' and photo.tag != 'skip' %}
-
- {{ photo.tag[0] | upper }}
-
+ {% if photo.tag == 'journal' %}
+ J
+ {% elif photo.tag == 'story' %}
+ S
+ {% elif photo.tag == 'skip' %}
+ X
{% endif %}
{% endfor %}
@@ -100,6 +101,11 @@
class="btn btn-circle btn-lg btn-ghost border-2 border-info text-2xl"
onclick="mobileApp && mobileApp.doTag('story')">S
+
+ {# Thumbnail strip — all photos, colored dot per tag, tap to jump #}
+
@@ -274,6 +280,7 @@ function mobileTriageApp(albumId, photos) {
if (queue.length === 0) {
showCompletion();
updateProgress();
+ updateThumbStrip();
return;
}
@@ -382,6 +389,7 @@ function mobileTriageApp(albumId, photos) {
updateProgress();
showCard();
+ updateThumbStrip();
}
// ── Undo ─────────────────────────────────────────────────────────────
@@ -406,10 +414,90 @@ function mobileTriageApp(albumId, photos) {
updateProgress();
showCard();
+ updateThumbStrip();
+ }
+
+ // ── Thumbnail strip ──────────────────────────────────────────────────
+
+ const thumbStrip = document.getElementById('m-thumb-strip');
+
+ function buildThumbStrip() {
+ thumbStrip.innerHTML = '';
+ photos.forEach(photo => {
+ const wrap = document.createElement('div');
+ wrap.className = 'relative flex-none cursor-pointer';
+ wrap.style.cssText = 'width:44px;height:44px;';
+ wrap.dataset.thumbId = photo.id;
+ wrap.addEventListener('click', () => jumpToPhoto(photo));
+
+ const img = document.createElement('img');
+ img.src = `/proxy/thumb/${photo.id}`;
+ img.style.cssText = 'width:100%;height:100%;object-fit:cover;border-radius:4px;border:2px solid transparent;transition:border-color 0.15s;display:block;';
+ img.draggable = false;
+ wrap.appendChild(img);
+
+ const dot = document.createElement('div');
+ dot.style.cssText = 'position:absolute;bottom:2px;left:2px;width:7px;height:7px;border-radius:50%;display:none;border:1px solid rgba(0,0,0,0.3);';
+ wrap.appendChild(dot);
+
+ thumbStrip.appendChild(wrap);
+ });
+ updateThumbStrip();
+ }
+
+ function updateThumbStrip() {
+ const currentId = queue.length > 0 ? queue[0].id : null;
+ photos.forEach(photo => {
+ const wrap = thumbStrip.querySelector(`[data-thumb-id="${photo.id}"]`);
+ if (!wrap) return;
+ const img = wrap.querySelector('img');
+ const dot = wrap.querySelector('div');
+
+ img.style.borderColor = photo.id === currentId ? '#fff' : 'transparent';
+ img.style.boxShadow = photo.id === currentId ? '0 0 0 1px rgba(0,0,0,0.4)' : 'none';
+
+ if (photo.tag === 'journal') {
+ dot.style.display = '';
+ dot.style.background = '#4ade80';
+ } else if (photo.tag === 'story') {
+ dot.style.display = '';
+ dot.style.background = '#38bdf8';
+ } else if (photo.tag === 'skip') {
+ dot.style.display = '';
+ dot.style.background = '#64748b';
+ } else {
+ dot.style.display = 'none';
+ }
+ });
+
+ if (currentId) {
+ const currentWrap = thumbStrip.querySelector(`[data-thumb-id="${currentId}"]`);
+ if (currentWrap) currentWrap.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' });
+ }
+ }
+
+ async function jumpToPhoto(photo) {
+ const queueIdx = queue.findIndex(p => p.id === photo.id);
+ if (queueIdx !== -1) queue.splice(queueIdx, 1);
+
+ if (photo.tag !== 'untagged') taggedCount--;
+ const prevTag = photo.tag;
+ photo.tag = 'untagged';
+ queue.unshift(photo);
+
+ await fetch('/triage/tag', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ album_id: albumId, asset_id: photo.id, tag: 'untagged' }),
+ });
+
+ updateProgress();
+ updateThumbStrip();
+ showCard();
}
// ── Public API ───────────────────────────────────────────────────────
- return { doTag, undo, showCard };
+ return { doTag, undo, showCard, buildThumbStrip, updateThumbStrip };
}
// ── View switching on load ───────────────────────────────────────────────────
@@ -427,6 +515,7 @@ document.addEventListener('DOMContentLoaded', () => {
document.getElementById('m-progress-text').textContent = `${taggedCount} / ${photos.length} tagged`;
document.getElementById('m-progress-bar').style.width =
photos.length > 0 ? `${(taggedCount / photos.length) * 100}%` : '0%';
+ mobileApp.buildThumbStrip();
mobileApp.showCard();
}
// Desktop: nothing extra needed — Alpine handles it