improve gallery
This commit is contained in:
parent
68c15fb367
commit
8efca53e8e
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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) => ({
|
||||||
'&': '&',
|
'&': '&',
|
||||||
@ -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();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user