diff --git a/frontend/src/routes/art/+page.svelte b/frontend/src/routes/art/+page.svelte index 468ca50..4f576b5 100644 --- a/frontend/src/routes/art/+page.svelte +++ b/frontend/src/routes/art/+page.svelte @@ -27,9 +27,25 @@ // screens; desktop and portrait art stay upright). Aspect is read off the loaded image. let landscape = $state(false); - function onKey(e) { - if (e.key === 'Escape' && zoom) zoom = false; + // Desktop zoom: inside the lightbox, magnify the artwork and pan by moving the cursor + // (transform-origin tracks the pointer). Mobile keeps native pinch — the Zoom button is + // hidden there. ox/oy are the transform-origin in %. + let zoomed = $state(false); + let ox = $state(50), oy = $state(50); + function enterZoom() { ox = 50; oy = 50; zoomed = true; } + function panZoom(e) { + const r = e.currentTarget.getBoundingClientRect(); + ox = Math.max(0, Math.min(100, ((e.clientX - r.left) / r.width) * 100)); + oy = Math.max(0, Math.min(100, ((e.clientY - r.top) / r.height) * 100)); } + + function onKey(e) { + if (e.key !== 'Escape') return; + if (zoomed) zoomed = false; // Escape steps out of zoom first, then closes + else if (zoom) zoom = false; + } + // Leaving the lightbox always drops zoom too, so re-opening starts framed. + $effect(() => { if (!zoom) zoomed = false; }); // Move focus to the lightbox when it opens, so Escape/Enter work and focus is trapped sanely. $effect(() => { if (zoom && lightboxEl) lightboxEl.focus(); }); @@ -218,15 +234,33 @@ {#if zoom && art} - + + {#if zoomed} + + + Move to look closer · click to zoom out + {:else} + + + {#if isWood}{@render woodRails()}{/if} + {art.title} + + {art.title}{#if art.artist}·{art.artist}{/if} + - {art.title}{#if art.artist}·{art.artist}{/if} - - + {/if} + {/if}