Art frames: add Black frame; thicker full-screen rail; rail-only top of thickness slider
- Black frame (no grain) added after Silver — a satin charcoal moulding in the metals family. - Full-screen rail bumped (clamp 18–36px) so the moulding reads as thick as the page view against the much larger image; mat held. - Thickness slider extended to 1.9× and the mat now caps at 1.5× (min()), so the top of the slider thickens only the wood while the white border stays put. Applies to the full-screen frame too. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
{ id: 'mahogany', label: 'Mahogany' },
|
||||
{ id: 'gold', label: 'Gold' },
|
||||
{ id: 'silver', label: 'Silver' },
|
||||
{ id: 'black', label: 'Black' },
|
||||
{ id: 'none', label: 'No frame' },
|
||||
];
|
||||
|
||||
@@ -16,7 +17,7 @@
|
||||
let state = $state('loading'); // loading | ready | empty
|
||||
let zoom = $state(false);
|
||||
let frame = $state('walnut');
|
||||
let thickness = $state(1); // frame-scale multiplier, 0.7–1.5
|
||||
let thickness = $state(1); // frame-scale multiplier, 0.7–1.9 (mat caps at 1.5)
|
||||
|
||||
let who = $derived(
|
||||
art ? [art.artist || 'Unknown artist', art.date_text].filter(Boolean) : []
|
||||
@@ -27,7 +28,7 @@
|
||||
const saved = localStorage.getItem('ub_art_frame');
|
||||
if (saved && FRAMES.some((f) => f.id === saved)) frame = saved;
|
||||
const t = parseFloat(localStorage.getItem('ub_art_thickness'));
|
||||
if (t >= 0.7 && t <= 1.5) thickness = t;
|
||||
if (t >= 0.7 && t <= 1.9) thickness = t;
|
||||
} catch { /* private mode — defaults are fine */ }
|
||||
try {
|
||||
art = await getJSON('/api/art/today');
|
||||
@@ -117,7 +118,7 @@
|
||||
{#if frame !== 'none'}
|
||||
<div class="thickness">
|
||||
<span class="frames-label">Thickness</span>
|
||||
<input type="range" min="0.7" max="1.5" step="0.05"
|
||||
<input type="range" min="0.7" max="1.9" step="0.05"
|
||||
bind:value={thickness} oninput={saveThickness} aria-label="Frame thickness" />
|
||||
</div>
|
||||
{/if}
|
||||
@@ -204,8 +205,10 @@
|
||||
switching frames never reflows the page. */
|
||||
.frame {
|
||||
box-sizing: border-box;
|
||||
/* Rail scales across the whole slider; the mat caps at scale 1.5 so the top of the
|
||||
slider thickens only the moulding (wood), holding the white border steady. */
|
||||
--rail: calc(clamp(11px, 2.3vw, 22px) * var(--frame-scale, 1));
|
||||
--mat: calc(clamp(10px, 2.4vw, 22px) * var(--frame-scale, 1));
|
||||
--mat: calc(clamp(10px, 2.4vw, 22px) * min(var(--frame-scale, 1), 1.5));
|
||||
border: none; cursor: zoom-in; background: none;
|
||||
position: relative; line-height: 0; display: inline-block; max-width: 100%;
|
||||
border-radius: 4px; padding: var(--rail);
|
||||
@@ -241,6 +244,13 @@
|
||||
inset 0 2px 3px rgba(255, 255, 255, 0.75),
|
||||
inset 0 -3px 9px rgba(60, 70, 85, 0.42);
|
||||
}
|
||||
.frame--black {
|
||||
background: linear-gradient(135deg, #2a2c30, #15171a 45%, #25282c 60%, #101113);
|
||||
box-shadow: 0 24px 58px rgba(20, 30, 45, 0.30),
|
||||
inset 0 0 0 1px rgba(255, 255, 255, 0.08),
|
||||
inset 0 2px 3px rgba(255, 255, 255, 0.10),
|
||||
inset 0 -3px 9px rgba(0, 0, 0, 0.60);
|
||||
}
|
||||
|
||||
/* Mitered (45°) corner joints for the woods — each seam runs from the outer corner to
|
||||
the mat, sized to the rail width so it tracks the thickness slider. */
|
||||
@@ -310,6 +320,7 @@
|
||||
.swatch--mahogany { background: linear-gradient(150deg, #5a241a, #7e3826 55%, #3a160e); }
|
||||
.swatch--gold { background: linear-gradient(150deg, #c79a45, #ecd293 55%, #a9772f); }
|
||||
.swatch--silver { background: linear-gradient(150deg, #aab1bb, #edf0f3 55%, #98a0ab); }
|
||||
.swatch--black { background: linear-gradient(150deg, #34373c, #16181b 55%, #0c0d0f); }
|
||||
.swatch--none { background: linear-gradient(150deg, #ffffff, #ece6da); }
|
||||
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
|
||||
|
||||
@@ -333,8 +344,8 @@
|
||||
framed piece — including the bottom rail — always fits on screen. */
|
||||
.lb-frame {
|
||||
cursor: zoom-out; max-width: 92vw;
|
||||
--rail: calc(clamp(14px, 1.4vw, 26px) * var(--frame-scale, 1));
|
||||
--mat: calc(clamp(16px, 1.6vw, 30px) * var(--frame-scale, 1));
|
||||
--rail: calc(clamp(18px, 1.9vw, 36px) * var(--frame-scale, 1));
|
||||
--mat: calc(clamp(16px, 1.6vw, 30px) * min(var(--frame-scale, 1), 1.5));
|
||||
}
|
||||
.lb-frame.frame--none { --rail: 0px; --mat: 0px; } /* bare art fills the screen */
|
||||
.lb-frame img { max-width: 86vw; max-height: 66vh; width: auto; height: auto; object-fit: contain; }
|
||||
|
||||
Reference in New Issue
Block a user