Add lightbox with download button + more photos per tool

This commit is contained in:
2026-05-02 09:27:08 +02:00
parent ae0e150bc1
commit 095f448c10
3 changed files with 76 additions and 2 deletions
+42 -2
View File
@@ -149,8 +149,9 @@ async function saveTool() {
async function openToolDetail(id) { async function openToolDetail(id) {
const t = await api.get(`/api/tools/${id}`); const t = await api.get(`/api/tools/${id}`);
const rents = await api.get(`/api/rentals?tool_id=${id}`); const rents = await api.get(`/api/rentals?tool_id=${id}`);
const gallery = t.images.length ? t.images.map(img => const imgUrls = t.images.map(img => `/uploads/tools/${img.filename}`);
`<img src="/uploads/tools/${img.filename}" class="${img.is_main?'main-img':''}" title="${img.is_main?'Principale':''}" onclick="setMainImage(${id},${img.id})"/>` const gallery = t.images.length ? t.images.map((img, idx) =>
`<img src="/uploads/tools/${img.filename}" class="${img.is_main?'main-img':''}" title="Cliquer pour agrandir" onclick="openLightbox(${JSON.stringify(imgUrls).replace(/"/g,'&quot;')}, ${idx})"/>`
).join('') : '<span style="color:var(--muted)">Aucune photo</span>'; ).join('') : '<span style="color:var(--muted)">Aucune photo</span>';
document.getElementById('tool-detail-content').innerHTML = ` document.getElementById('tool-detail-content').innerHTML = `
@@ -509,5 +510,44 @@ function statusLabel(s) {
return {confirmed:'Confirmée', ongoing:'En cours', returned:'Retournée', cancelled:'Annulée'}[s] || s; return {confirmed:'Confirmée', ongoing:'En cours', returned:'Retournée', cancelled:'Annulée'}[s] || s;
} }
// ─── Lightbox ───────────────────────────────────────────────────────────────
let _lbImages = [], _lbIdx = 0;
function openLightbox(images, idx) {
_lbImages = images;
_lbIdx = idx;
_lbRender();
document.getElementById('lightbox').classList.remove('hidden');
document.addEventListener('keydown', _lbKey);
}
function closeLightbox() {
document.getElementById('lightbox').classList.add('hidden');
document.removeEventListener('keydown', _lbKey);
}
function lightboxNav(dir) {
_lbIdx = (_lbIdx + dir + _lbImages.length) % _lbImages.length;
_lbRender();
}
function _lbRender() {
const url = _lbImages[_lbIdx];
const img = document.getElementById('lightbox-img');
img.src = url;
document.getElementById('lightbox-counter').textContent = `${_lbIdx + 1} / ${_lbImages.length}`;
const dl = document.getElementById('lightbox-download');
dl.href = url;
dl.download = url.split('/').pop();
document.querySelector('.lightbox-prev').style.display = _lbImages.length > 1 ? '' : 'none';
document.querySelector('.lightbox-next').style.display = _lbImages.length > 1 ? '' : 'none';
}
function _lbKey(e) {
if (e.key === 'ArrowLeft') lightboxNav(-1);
else if (e.key === 'ArrowRight') lightboxNav(1);
else if (e.key === 'Escape') closeLightbox();
}
// ─── Init ─────────────────────────────────────────────────────────────────── // ─── Init ───────────────────────────────────────────────────────────────────
loadDashboard(); loadDashboard();
+19
View File
@@ -180,3 +180,22 @@ input[type="file"] { padding: 6px; font-size: 0.8rem; }
.nav-item { white-space: nowrap; } .nav-item { white-space: nowrap; }
.logo { display: none; } .logo { display: none; }
} }
/* Lightbox */
.lightbox { position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center; }
.lightbox.hidden { display: none; }
.lightbox-overlay { position: absolute; inset: 0; background: rgba(0,0,0,0.92); }
.lightbox-content { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; max-width: 90vw; max-height: 90vh; gap: 12px; }
.lightbox-content img { max-width: 85vw; max-height: 80vh; object-fit: contain; border-radius: 8px; display: block; }
.lightbox-close { position: fixed; top: 16px; right: 20px; background: rgba(255,255,255,0.1); border: none; color: #fff; font-size: 1.4rem; cursor: pointer; border-radius: 50%; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; }
.lightbox-close:hover { background: rgba(255,255,255,0.25); }
.lightbox-nav { position: fixed; top: 50%; transform: translateY(-50%); background: rgba(255,255,255,0.1); border: none; color: #fff; font-size: 2.5rem; cursor: pointer; padding: 12px 16px; border-radius: 8px; line-height: 1; }
.lightbox-nav:hover { background: rgba(255,255,255,0.25); }
.lightbox-prev { left: 12px; }
.lightbox-next { right: 12px; }
.lightbox-footer { display: flex; align-items: center; gap: 16px; }
.lightbox-footer #lightbox-counter { color: rgba(255,255,255,0.6); font-size: 0.85rem; }
/* Tool gallery — images cliquables */
.tool-detail-gallery img { cursor: zoom-in; transition: opacity 0.15s; }
.tool-detail-gallery img:hover { opacity: 0.85; }
+15
View File
@@ -216,6 +216,21 @@
</div> </div>
</div> </div>
<!-- LIGHTBOX -->
<div id="lightbox" class="lightbox hidden">
<div class="lightbox-overlay" onclick="closeLightbox()"></div>
<div class="lightbox-content">
<button class="lightbox-close" onclick="closeLightbox()"></button>
<button class="lightbox-nav lightbox-prev" onclick="lightboxNav(-1)"></button>
<img id="lightbox-img" src="" alt=""/>
<button class="lightbox-nav lightbox-next" onclick="lightboxNav(1)"></button>
<div class="lightbox-footer">
<span id="lightbox-counter"></span>
<a id="lightbox-download" href="" download class="btn btn-primary btn-sm">⬇ Télécharger</a>
</div>
</div>
</div>
<script src="/static/app.js"></script> <script src="/static/app.js"></script>
</body> </body>
</html> </html>