fix: mtime filter + lightbox navigation (arrows, swipe, keyboard)
This commit is contained in:
@@ -106,16 +106,31 @@
|
||||
display: none; position: fixed; inset: 0; z-index: 1000;
|
||||
background: rgba(0,0,0,.92); backdrop-filter: blur(8px);
|
||||
align-items: center; justify-content: center; padding: 1.5rem;
|
||||
gap: 1rem;
|
||||
}
|
||||
.lightbox.open { display: flex; }
|
||||
|
||||
.lb-nav-btn {
|
||||
flex-shrink: 0; width: 44px; height: 44px; border-radius: 50%;
|
||||
border: 1px solid rgba(255,255,255,.2); background: rgba(255,255,255,.08);
|
||||
color: #fff; font-size: 1.3rem; cursor: pointer; display: flex;
|
||||
align-items: center; justify-content: center; transition: background .15s;
|
||||
user-select: none;
|
||||
}
|
||||
.lb-nav-btn:hover:not(:disabled) { background: rgba(255,255,255,.18); }
|
||||
.lb-nav-btn:disabled { opacity: .2; cursor: default; }
|
||||
|
||||
.lb-modal {
|
||||
background: var(--surface); border: 1px solid var(--border);
|
||||
border-radius: 16px; overflow: hidden;
|
||||
max-width: min(900px, 95vw); width: 100%;
|
||||
max-width: min(860px, calc(95vw - 110px)); width: 100%;
|
||||
display: flex; flex-direction: column; max-height: 95vh;
|
||||
}
|
||||
|
||||
.lb-counter {
|
||||
font-size: .75rem; color: var(--text-muted); white-space: nowrap;
|
||||
}
|
||||
|
||||
.lb-header {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
padding: .75rem 1.1rem; border-bottom: 1px solid var(--border);
|
||||
@@ -247,6 +262,7 @@
|
||||
|
||||
<!-- ── Lightbox ─────────────────────────────────────────────────────────────── -->
|
||||
<div class="lightbox" id="lightbox" onclick="lbBackdropClose(event)">
|
||||
<button class="lb-nav-btn" id="lb-prev" onclick="lbNavigate(-1);event.stopPropagation()">‹</button>
|
||||
<div class="lb-modal">
|
||||
|
||||
<!-- En-tête -->
|
||||
@@ -255,6 +271,7 @@
|
||||
<div class="lb-date" id="lb-date">—</div>
|
||||
<div class="lb-id" id="lb-id"></div>
|
||||
</div>
|
||||
<span class="lb-counter" id="lb-counter"></span>
|
||||
<button class="lb-close-btn" onclick="closeLightbox()">✕</button>
|
||||
</div>
|
||||
|
||||
@@ -294,6 +311,7 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<button class="lb-nav-btn" id="lb-next" onclick="lbNavigate(1);event.stopPropagation()">›</button>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -302,6 +320,8 @@
|
||||
let currentPage = 1;
|
||||
let totalPages = 1;
|
||||
let allPhotos = [];
|
||||
let displayedPhotos = []; // photos actuellement dans la grille (après filtre statut)
|
||||
let currentIndex = -1; // index dans displayedPhotos
|
||||
let currentPhotoId = null;
|
||||
let currentPhotoData = null;
|
||||
|
||||
@@ -411,15 +431,17 @@ function updateFilterSummary(total) {
|
||||
// Rendu grille
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
function renderGrid(photos) {
|
||||
displayedPhotos = photos || [];
|
||||
const grid = document.getElementById('photo-grid');
|
||||
|
||||
if (!photos || !photos.length) {
|
||||
if (!displayedPhotos.length) {
|
||||
grid.innerHTML = `<div style="color:var(--text-muted);grid-column:1/-1;text-align:center;padding:2rem">
|
||||
📷 Aucune photo pour ces filtres</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
grid.innerHTML = photos.map(p => {
|
||||
// On utilise l'index (pas le JSON sérialisé) pour éviter les problèmes de quotes
|
||||
grid.innerHTML = displayedPhotos.map((p, idx) => {
|
||||
const pid = p.photo_id || p.id || '';
|
||||
const hasPending = p.print_pending > 0;
|
||||
const hasPrinting = p.print_printing > 0;
|
||||
@@ -433,7 +455,7 @@ function renderGrid(photos) {
|
||||
|
||||
return `
|
||||
<div class="photo-card ${hasPending || hasPrinting ? 'has-print' : ''}" id="card-${pid}"
|
||||
onclick="openLightbox(${JSON.stringify(p).replace(/'/g, ''')})">
|
||||
onclick="openLightboxIdx(${idx})">
|
||||
<img src="${p.thumb_url}" loading="lazy" alt="">
|
||||
${badge}${dateLabel}
|
||||
<div class="card-overlay">
|
||||
@@ -450,19 +472,31 @@ function renderGrid(photos) {
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Lightbox
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
function openLightbox(photo) {
|
||||
function openLightboxIdx(idx) {
|
||||
if (idx < 0 || idx >= displayedPhotos.length) return;
|
||||
currentIndex = idx;
|
||||
const photo = displayedPhotos[idx];
|
||||
currentPhotoData = photo;
|
||||
currentPhotoId = photo.photo_id || photo.id || '';
|
||||
|
||||
document.getElementById('lb-img').src = photo.full_url || photo.thumb_url;
|
||||
document.getElementById('lb-date').textContent = photo.date_label || '—';
|
||||
document.getElementById('lb-id').textContent = currentPhotoId;
|
||||
document.getElementById('lb-btn-dl').href = photo.download_url || photo.full_url;
|
||||
document.getElementById('lb-img').src = photo.full_url || photo.thumb_url;
|
||||
document.getElementById('lb-date').textContent = photo.date_label || '—';
|
||||
document.getElementById('lb-id').textContent = currentPhotoId;
|
||||
document.getElementById('lb-btn-dl').href = photo.download_url || photo.full_url;
|
||||
document.getElementById('lb-counter').textContent = `${idx + 1} / ${displayedPhotos.length}`;
|
||||
|
||||
// Boutons nav
|
||||
document.getElementById('lb-prev').disabled = idx <= 0;
|
||||
document.getElementById('lb-next').disabled = idx >= displayedPhotos.length - 1;
|
||||
|
||||
_updateLbPrintPanel(photo);
|
||||
document.getElementById('lightbox').classList.add('open');
|
||||
}
|
||||
|
||||
function lbNavigate(dir) {
|
||||
openLightboxIdx(currentIndex + dir);
|
||||
}
|
||||
|
||||
function _updateLbPrintPanel(photo) {
|
||||
const panel = document.getElementById('lb-print-panel');
|
||||
const list = document.getElementById('lb-queue-list');
|
||||
@@ -496,12 +530,31 @@ function closeLightbox() {
|
||||
document.getElementById('lightbox').classList.remove('open');
|
||||
document.getElementById('lb-img').src = '';
|
||||
currentPhotoId = currentPhotoData = null;
|
||||
currentIndex = -1;
|
||||
}
|
||||
|
||||
function lbBackdropClose(e) {
|
||||
if (e.target === document.getElementById('lightbox')) closeLightbox();
|
||||
}
|
||||
document.addEventListener('keydown', e => { if (e.key === 'Escape') closeLightbox(); });
|
||||
|
||||
// Clavier : Échap + flèches
|
||||
document.addEventListener('keydown', e => {
|
||||
const lb = document.getElementById('lightbox');
|
||||
if (!lb.classList.contains('open')) return;
|
||||
if (e.key === 'Escape') { closeLightbox(); }
|
||||
else if (e.key === 'ArrowLeft') { lbNavigate(-1); }
|
||||
else if (e.key === 'ArrowRight') { lbNavigate(1); }
|
||||
});
|
||||
|
||||
// Swipe tactile
|
||||
let _touchX = 0;
|
||||
document.getElementById('lightbox').addEventListener('touchstart', e => {
|
||||
_touchX = e.touches[0].clientX;
|
||||
}, { passive: true });
|
||||
document.getElementById('lightbox').addEventListener('touchend', e => {
|
||||
const dx = e.changedTouches[0].clientX - _touchX;
|
||||
if (Math.abs(dx) > 50) lbNavigate(dx < 0 ? 1 : -1);
|
||||
}, { passive: true });
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Actions impression
|
||||
@@ -586,15 +639,23 @@ async function _refreshPhotoData(pid) {
|
||||
try {
|
||||
const data = await api('GET', `/admin/api/gallery/photos?${_buildParams(currentPage)}`);
|
||||
allPhotos = data.photos || [];
|
||||
const photo = allPhotos.find(p => (p.photo_id || p.id) === pid);
|
||||
if (photo && currentPhotoId === pid) {
|
||||
currentPhotoData = photo;
|
||||
_updateLbPrintPanel(photo);
|
||||
}
|
||||
let photos = allPhotos;
|
||||
if (statusFilter === 'pending') photos = allPhotos.filter(p => p.print_pending > 0 || p.print_printing > 0);
|
||||
renderGrid(photos);
|
||||
document.getElementById('pending-count').textContent = allPhotos.filter(p => p.print_pending > 0).length;
|
||||
|
||||
// Si lightbox ouverte sur cette photo, mettre à jour le panel impression
|
||||
if (currentPhotoId === pid) {
|
||||
const newIdx = displayedPhotos.findIndex(p => (p.photo_id || p.id) === pid);
|
||||
if (newIdx >= 0) {
|
||||
currentIndex = newIdx;
|
||||
currentPhotoData = displayedPhotos[newIdx];
|
||||
_updateLbPrintPanel(currentPhotoData);
|
||||
document.getElementById('lb-prev').disabled = newIdx <= 0;
|
||||
document.getElementById('lb-next').disabled = newIdx >= displayedPhotos.length - 1;
|
||||
document.getElementById('lb-counter').textContent = `${newIdx + 1} / ${displayedPhotos.length}`;
|
||||
}
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user