improve gallery
This commit is contained in:
parent
68c15fb367
commit
8efca53e8e
@ -623,6 +623,14 @@ footer .audio-player-container {
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(145deg, #ffffff, #f6f8fc);
|
||||
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 */
|
||||
@ -651,11 +659,12 @@ footer .audio-player-container {
|
||||
.thumbnail {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.thumbnail-fallback {
|
||||
object-fit: contain;
|
||||
object-fit: cover;
|
||||
background: #e5e5e5;
|
||||
}
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
position: fixed;
|
||||
z-index: 3000;
|
||||
inset: 0;
|
||||
--gallery-edge-gap: 10px;
|
||||
background-color: rgba(0, 0, 0, 0.82);
|
||||
background-image:
|
||||
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 {
|
||||
position: absolute;
|
||||
inset: 82px 22px 96px;
|
||||
inset: var(--gallery-edge-gap);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@ -42,8 +43,8 @@
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
max-width: min(96vw, calc(100vw - 80px));
|
||||
max-height: calc(100vh - 190px);
|
||||
max-width: calc(100vw - (var(--gallery-edge-gap) * 2));
|
||||
max-height: calc(100vh - (var(--gallery-edge-gap) * 2));
|
||||
object-fit: contain;
|
||||
margin: auto;
|
||||
display: block;
|
||||
@ -258,7 +259,7 @@
|
||||
#gallery-filename,
|
||||
#gallery-position {
|
||||
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-radius: 8px;
|
||||
padding: 0.45rem 0.72rem;
|
||||
@ -285,10 +286,10 @@
|
||||
background:
|
||||
linear-gradient(
|
||||
90deg,
|
||||
rgba(255, 255, 255, 0.95) 0%,
|
||||
rgba(255, 255, 255, 0.95) var(--filename-progress),
|
||||
rgba(0, 0, 0, 0.62) var(--filename-progress),
|
||||
rgba(0, 0, 0, 0.62) 100%
|
||||
rgba(255, 255, 255, 0.56) 0%,
|
||||
rgba(255, 255, 255, 0.56) var(--filename-progress),
|
||||
rgba(0, 0, 0, 0.44) var(--filename-progress),
|
||||
rgba(0, 0, 0, 0.44) 100%
|
||||
);
|
||||
z-index: 0;
|
||||
}
|
||||
@ -310,7 +311,7 @@
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0.45rem 0.72rem;
|
||||
padding: inherit;
|
||||
box-sizing: border-box;
|
||||
z-index: 2;
|
||||
overflow: hidden;
|
||||
@ -365,13 +366,17 @@
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
#gallery-modal {
|
||||
--gallery-edge-gap: 8px;
|
||||
}
|
||||
|
||||
#gallery-stage {
|
||||
inset: 74px 10px 110px;
|
||||
inset: var(--gallery-edge-gap);
|
||||
}
|
||||
|
||||
#gallery-modal-content {
|
||||
max-width: calc(100vw - 20px);
|
||||
max-height: calc(100vh - 210px);
|
||||
max-width: calc(100vw - (var(--gallery-edge-gap) * 2));
|
||||
max-height: calc(100vh - (var(--gallery-edge-gap) * 2));
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
@ -453,13 +458,17 @@
|
||||
}
|
||||
|
||||
@media (max-height: 520px) and (orientation: landscape) {
|
||||
#gallery-modal {
|
||||
--gallery-edge-gap: 6px;
|
||||
}
|
||||
|
||||
#gallery-stage {
|
||||
inset: 44px 10px 60px;
|
||||
inset: var(--gallery-edge-gap);
|
||||
}
|
||||
|
||||
#gallery-modal-content {
|
||||
max-width: calc(100vw - 20px);
|
||||
max-height: calc(100vh - 112px);
|
||||
max-width: calc(100vw - (var(--gallery-edge-gap) * 2));
|
||||
max-height: calc(100vh - (var(--gallery-edge-gap) * 2));
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@ if (typeof currentGalleryIndex === "undefined") {
|
||||
}
|
||||
|
||||
let currentExifRequestId = 0;
|
||||
const previewRefreshInFlight = new Set();
|
||||
|
||||
function encodeGalleryPath(relUrl) {
|
||||
if (!relUrl) {
|
||||
@ -40,6 +41,73 @@ function encodeGalleryPath(relUrl) {
|
||||
.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) {
|
||||
return String(value === undefined || value === null ? '' : value).replace(/[&<>"']/g, (char) => ({
|
||||
'&': '&',
|
||||
@ -276,6 +344,11 @@ function showGalleryNav() {
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function hideGalleryNav() {
|
||||
clearTimeout(navHideTimer);
|
||||
document.querySelectorAll('.gallery-nav').forEach(btn => btn.classList.add('nav-hidden'));
|
||||
}
|
||||
|
||||
function clamp(value, min, max) {
|
||||
return Math.min(Math.max(value, min), max);
|
||||
}
|
||||
@ -375,6 +448,7 @@ function showGalleryImage(relUrl) {
|
||||
clearTimeout(loaderTimeout);
|
||||
loader.style.display = 'none';
|
||||
updateFilenameDisplay(relUrl);
|
||||
refreshBrowserThumbnailIfMissing(relUrl);
|
||||
|
||||
// Select all current images in the gallery stage
|
||||
const existingImages = stage.querySelectorAll('img');
|
||||
@ -449,8 +523,12 @@ function showGalleryImage(relUrl) {
|
||||
|
||||
function preloadNextImage() {
|
||||
if (currentGalleryIndex < currentGalleryImages.length - 1) {
|
||||
const nextRelUrl = currentGalleryImages[currentGalleryIndex + 1];
|
||||
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;
|
||||
pinchStartTranslateX = currentTranslateX;
|
||||
pinchStartTranslateY = currentTranslateY;
|
||||
showGalleryNav();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -736,7 +813,11 @@ function handlePinchMove(e) {
|
||||
currentTranslateX = pinchStartTranslateX + (midX - pinchStartMidX);
|
||||
currentTranslateY = pinchStartTranslateY + (midY - pinchStartMidY);
|
||||
applyImageTransform(e.currentTarget);
|
||||
if (currentScale > 1.01) {
|
||||
showGalleryNav();
|
||||
} else {
|
||||
hideGalleryNav();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -776,6 +857,9 @@ function handlePinchEnd(e) {
|
||||
currentScale = 1;
|
||||
currentTranslateX = 0;
|
||||
currentTranslateY = 0;
|
||||
applyImageTransform(image);
|
||||
hideGalleryNav();
|
||||
return;
|
||||
}
|
||||
applyImageTransform(image);
|
||||
showGalleryNav();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user