improve gallery

This commit is contained in:
lelo 2026-02-28 19:07:28 +00:00
parent 68c15fb367
commit 8efca53e8e
3 changed files with 121 additions and 19 deletions

View File

@ -623,6 +623,14 @@ footer .audio-player-container {
border-radius: 12px; border-radius: 12px;
background: linear-gradient(145deg, #ffffff, #f6f8fc); background: linear-gradient(145deg, #ffffff, #f6f8fc);
box-shadow: var(--card-shadow); box-shadow: var(--card-shadow);
aspect-ratio: 1 / 1;
}
.image-item .image-link {
display: block;
width: 100%;
height: 100%;
line-height: 0;
} }
/* the filename overlay, centered at bottom */ /* the filename overlay, centered at bottom */
@ -651,11 +659,12 @@ footer .audio-player-container {
.thumbnail { .thumbnail {
width: 100%; width: 100%;
height: 100%; height: 100%;
display: block;
object-fit: cover; object-fit: cover;
} }
.thumbnail-fallback { .thumbnail-fallback {
object-fit: contain; object-fit: cover;
background: #e5e5e5; background: #e5e5e5;
} }

View File

@ -22,6 +22,7 @@
position: fixed; position: fixed;
z-index: 3000; z-index: 3000;
inset: 0; inset: 0;
--gallery-edge-gap: 10px;
background-color: rgba(0, 0, 0, 0.82); background-color: rgba(0, 0, 0, 0.82);
background-image: background-image:
radial-gradient(circle at 50% 15%, rgba(42, 42, 42, 0.52), rgba(8, 8, 8, 0.95) 56%, #000 100%); radial-gradient(circle at 50% 15%, rgba(42, 42, 42, 0.52), rgba(8, 8, 8, 0.95) 56%, #000 100%);
@ -33,7 +34,7 @@
#gallery-stage { #gallery-stage {
position: absolute; position: absolute;
inset: 82px 22px 96px; inset: var(--gallery-edge-gap);
cursor: pointer; cursor: pointer;
} }
@ -42,8 +43,8 @@
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
max-width: min(96vw, calc(100vw - 80px)); max-width: calc(100vw - (var(--gallery-edge-gap) * 2));
max-height: calc(100vh - 190px); max-height: calc(100vh - (var(--gallery-edge-gap) * 2));
object-fit: contain; object-fit: contain;
margin: auto; margin: auto;
display: block; display: block;
@ -258,7 +259,7 @@
#gallery-filename, #gallery-filename,
#gallery-position { #gallery-position {
color: #fff; color: #fff;
background: rgba(0, 0, 0, 0.6); background: rgba(0, 0, 0, 0.42);
border: 1px solid rgba(255, 255, 255, 0.16); border: 1px solid rgba(255, 255, 255, 0.16);
border-radius: 8px; border-radius: 8px;
padding: 0.45rem 0.72rem; padding: 0.45rem 0.72rem;
@ -285,10 +286,10 @@
background: background:
linear-gradient( linear-gradient(
90deg, 90deg,
rgba(255, 255, 255, 0.95) 0%, rgba(255, 255, 255, 0.56) 0%,
rgba(255, 255, 255, 0.95) var(--filename-progress), rgba(255, 255, 255, 0.56) var(--filename-progress),
rgba(0, 0, 0, 0.62) var(--filename-progress), rgba(0, 0, 0, 0.44) var(--filename-progress),
rgba(0, 0, 0, 0.62) 100% rgba(0, 0, 0, 0.44) 100%
); );
z-index: 0; z-index: 0;
} }
@ -310,7 +311,7 @@
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
padding: 0.45rem 0.72rem; padding: inherit;
box-sizing: border-box; box-sizing: border-box;
z-index: 2; z-index: 2;
overflow: hidden; overflow: hidden;
@ -365,13 +366,17 @@
} }
@media (max-width: 860px) { @media (max-width: 860px) {
#gallery-modal {
--gallery-edge-gap: 8px;
}
#gallery-stage { #gallery-stage {
inset: 74px 10px 110px; inset: var(--gallery-edge-gap);
} }
#gallery-modal-content { #gallery-modal-content {
max-width: calc(100vw - 20px); max-width: calc(100vw - (var(--gallery-edge-gap) * 2));
max-height: calc(100vh - 210px); max-height: calc(100vh - (var(--gallery-edge-gap) * 2));
border-radius: 10px; border-radius: 10px;
} }
@ -453,13 +458,17 @@
} }
@media (max-height: 520px) and (orientation: landscape) { @media (max-height: 520px) and (orientation: landscape) {
#gallery-modal {
--gallery-edge-gap: 6px;
}
#gallery-stage { #gallery-stage {
inset: 44px 10px 60px; inset: var(--gallery-edge-gap);
} }
#gallery-modal-content { #gallery-modal-content {
max-width: calc(100vw - 20px); max-width: calc(100vw - (var(--gallery-edge-gap) * 2));
max-height: calc(100vh - 112px); max-height: calc(100vh - (var(--gallery-edge-gap) * 2));
border-radius: 8px; border-radius: 8px;
} }

View File

@ -29,6 +29,7 @@ if (typeof currentGalleryIndex === "undefined") {
} }
let currentExifRequestId = 0; let currentExifRequestId = 0;
const previewRefreshInFlight = new Set();
function encodeGalleryPath(relUrl) { function encodeGalleryPath(relUrl) {
if (!relUrl) { if (!relUrl) {
@ -40,6 +41,73 @@ function encodeGalleryPath(relUrl) {
.join('/'); .join('/');
} }
function findBrowserThumbnailByRelUrl(relUrl) {
if (!relUrl) {
return null;
}
const links = document.querySelectorAll('.image-link[data-url]');
for (const link of links) {
if ((link.dataset.url || '') === relUrl) {
return link.querySelector('img.thumbnail');
}
}
return null;
}
function isFallbackThumbnail(imgEl) {
if (!imgEl) {
return false;
}
const src = imgEl.getAttribute('src') || '';
return imgEl.classList.contains('thumbnail-fallback') || src.startsWith('data:image/');
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function refreshBrowserThumbnailIfMissing(relUrl) {
if (!relUrl || previewRefreshInFlight.has(relUrl)) {
return;
}
const thumbImg = findBrowserThumbnailByRelUrl(relUrl);
if (!thumbImg || !isFallbackThumbnail(thumbImg)) {
return;
}
const baseThumbUrl = thumbImg.dataset.thumbUrl;
if (!baseThumbUrl) {
return;
}
previewRefreshInFlight.add(relUrl);
const separator = baseThumbUrl.includes('?') ? '&' : '?';
try {
for (let attempt = 0; attempt < 2; attempt++) {
const refreshUrl = `${baseThumbUrl}${separator}_=${Date.now()}-${attempt}`;
const response = await fetch(refreshUrl, { method: 'GET', cache: 'no-store' }).catch(() => null);
if (response && response.ok && response.status !== 204) {
thumbImg.classList.remove('thumbnail-fallback');
if (typeof handleThumbnailLoad === 'function') {
thumbImg.onload = () => handleThumbnailLoad(thumbImg);
}
if (typeof handleThumbnailError === 'function') {
thumbImg.onerror = () => handleThumbnailError(thumbImg);
}
thumbImg.src = refreshUrl;
return;
}
if (attempt === 0) {
await delay(250);
}
}
} finally {
previewRefreshInFlight.delete(relUrl);
}
}
function escapeHtml(value) { function escapeHtml(value) {
return String(value === undefined || value === null ? '' : value).replace(/[&<>"']/g, (char) => ({ return String(value === undefined || value === null ? '' : value).replace(/[&<>"']/g, (char) => ({
'&': '&amp;', '&': '&amp;',
@ -276,6 +344,11 @@ function showGalleryNav() {
}, 1000); }, 1000);
} }
function hideGalleryNav() {
clearTimeout(navHideTimer);
document.querySelectorAll('.gallery-nav').forEach(btn => btn.classList.add('nav-hidden'));
}
function clamp(value, min, max) { function clamp(value, min, max) {
return Math.min(Math.max(value, min), max); return Math.min(Math.max(value, min), max);
} }
@ -375,6 +448,7 @@ function showGalleryImage(relUrl) {
clearTimeout(loaderTimeout); clearTimeout(loaderTimeout);
loader.style.display = 'none'; loader.style.display = 'none';
updateFilenameDisplay(relUrl); updateFilenameDisplay(relUrl);
refreshBrowserThumbnailIfMissing(relUrl);
// Select all current images in the gallery stage // Select all current images in the gallery stage
const existingImages = stage.querySelectorAll('img'); const existingImages = stage.querySelectorAll('img');
@ -449,8 +523,12 @@ function showGalleryImage(relUrl) {
function preloadNextImage() { function preloadNextImage() {
if (currentGalleryIndex < currentGalleryImages.length - 1) { if (currentGalleryIndex < currentGalleryImages.length - 1) {
const nextRelUrl = currentGalleryImages[currentGalleryIndex + 1];
const nextImage = new Image(); const nextImage = new Image();
nextImage.src = '/media/' + currentGalleryImages[currentGalleryIndex + 1]; nextImage.onload = function () {
refreshBrowserThumbnailIfMissing(nextRelUrl);
};
nextImage.src = '/media/' + nextRelUrl;
} }
} }
@ -703,7 +781,6 @@ function handlePinchStart(e) {
pinchStartMidY = (e.touches[0].pageY + e.touches[1].pageY) / 2; pinchStartMidY = (e.touches[0].pageY + e.touches[1].pageY) / 2;
pinchStartTranslateX = currentTranslateX; pinchStartTranslateX = currentTranslateX;
pinchStartTranslateY = currentTranslateY; pinchStartTranslateY = currentTranslateY;
showGalleryNav();
return; return;
} }
@ -736,7 +813,11 @@ function handlePinchMove(e) {
currentTranslateX = pinchStartTranslateX + (midX - pinchStartMidX); currentTranslateX = pinchStartTranslateX + (midX - pinchStartMidX);
currentTranslateY = pinchStartTranslateY + (midY - pinchStartMidY); currentTranslateY = pinchStartTranslateY + (midY - pinchStartMidY);
applyImageTransform(e.currentTarget); applyImageTransform(e.currentTarget);
if (currentScale > 1.01) {
showGalleryNav(); showGalleryNav();
} else {
hideGalleryNav();
}
return; return;
} }
@ -776,6 +857,9 @@ function handlePinchEnd(e) {
currentScale = 1; currentScale = 1;
currentTranslateX = 0; currentTranslateX = 0;
currentTranslateY = 0; currentTranslateY = 0;
applyImageTransform(image);
hideGalleryNav();
return;
} }
applyImageTransform(image); applyImageTransform(image);
showGalleryNav(); showGalleryNav();