/art: landscape paintings rotate to fill the screen in fullscreen on portrait phones
Conditional 90° rotate of the fullscreen stage (frame + caption together): only when the artwork is landscape AND the screen is a narrow portrait phone — so a wide painting fills the long axis (turn phone to view level, tap to close). Portrait/square art and desktop stay upright. Landscape detected from the loaded image's natural dimensions; CSS decides WHEN via (orientation: portrait). Image caps use swapped vh/vw units post-rotation so the whole framed piece always fits. No screen-orientation lock API (unreliable on mobile web) — pure CSS transform. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,10 @@
|
||||
let frame = $state('walnut');
|
||||
let thickness = $state(1); // frame-scale multiplier, 0.7–1.9 (mat caps at 1.5)
|
||||
let lightboxEl = $state(null);
|
||||
// Wide paintings fill a portrait phone far better turned sideways: when the art is
|
||||
// landscape we rotate the fullscreen view 90° (CSS handles WHEN — only narrow+portrait
|
||||
// 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;
|
||||
@@ -103,7 +107,8 @@
|
||||
onclick={() => (zoom = true)} aria-label="Expand artwork">
|
||||
{#if isWood}{@render woodRails()}{/if}
|
||||
<span class="mat">
|
||||
<img src={art.image_url} alt={art.title} />
|
||||
<img src={art.image_url} alt={art.title}
|
||||
onload={(e) => (landscape = e.currentTarget.naturalWidth > e.currentTarget.naturalHeight)} />
|
||||
<span class="hint">
|
||||
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
@@ -154,12 +159,14 @@
|
||||
</div>
|
||||
|
||||
{#if zoom && art}
|
||||
<button class="lightbox" bind:this={lightboxEl} onclick={() => (zoom = false)} aria-label="Close artwork">
|
||||
<span class="frame frame--{frame} lb-frame" style="--frame-scale:{thickness}">
|
||||
{#if isWood}{@render woodRails()}{/if}
|
||||
<span class="mat"><img src={art.image_url_large || art.image_url} alt={art.title} /></span>
|
||||
<button class="lightbox" class:rotate={landscape} bind:this={lightboxEl} onclick={() => (zoom = false)} aria-label="Close artwork">
|
||||
<span class="lb-stage">
|
||||
<span class="frame frame--{frame} lb-frame" style="--frame-scale:{thickness}">
|
||||
{#if isWood}{@render woodRails()}{/if}
|
||||
<span class="mat"><img src={art.image_url_large || art.image_url} alt={art.title} /></span>
|
||||
</span>
|
||||
<span class="lb-cap">{art.title}{#if art.artist}<span class="sep">·</span>{art.artist}{/if}</span>
|
||||
</span>
|
||||
<span class="lb-cap">{art.title}{#if art.artist}<span class="sep">·</span>{art.artist}{/if}</span>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -390,8 +397,10 @@
|
||||
included) reads, like a piece hung on a real wall. */
|
||||
background: linear-gradient(180deg, #efe9dd, #e2dbcc);
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center; gap: 12px; padding: 2.5vmin;
|
||||
align-items: center; justify-content: center; padding: 2.5vmin;
|
||||
}
|
||||
/* frame + caption travel together so a rotated view turns as one piece */
|
||||
.lb-stage { display: flex; flex-direction: column; align-items: center; gap: 12px; }
|
||||
/* The full-screen view wears the same frame. Rail + mat are only a touch larger than the
|
||||
page (keeping the ~1:1 wood:white proportion), and the image is capped so the whole
|
||||
framed piece — including the bottom rail — always fits on screen. */
|
||||
@@ -414,4 +423,15 @@
|
||||
.lb-frame img { max-width: 72vw; max-height: 60vh; }
|
||||
.lb-frame.frame--none img { max-width: 92vw; max-height: 78vh; }
|
||||
}
|
||||
|
||||
/* Landscape artwork on a PORTRAIT phone: turn the whole stage 90° so the painting
|
||||
fills the long axis (turn the phone to view it level; tap anywhere to close). The
|
||||
image caps are in SWAPPED units — vh drives the on-screen long edge after rotation,
|
||||
vw the short edge — so it always fits. Desktop and portrait art never hit this. */
|
||||
@media (max-width: 640px) and (orientation: portrait) {
|
||||
.lightbox.rotate .lb-stage { transform: rotate(90deg); transform-origin: center; }
|
||||
.lightbox.rotate .lb-frame { max-width: 90vh; }
|
||||
.lightbox.rotate .lb-frame img { max-width: 82vh; max-height: 80vw; }
|
||||
.lightbox.rotate .lb-frame.frame--none img { max-width: 92vh; max-height: 92vw; }
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user