From 71fb16761b10aaaa23465376317a664458fe56b9 Mon Sep 17 00:00:00 2001 From: jay Date: Sun, 21 Jun 2026 17:02:26 -0400 Subject: [PATCH] Art frames round 3: natural wood grain, thickness slider, no-jump layout, polish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Oak grain is now a real feTurbulence noise field (organic wood, no drawn-on lines), with a soft light/shade for moulding roundness; miters kept. - Thickness slider (0.7–1.5×) scales rail + mat via --frame-scale, remembered locally; applies to both the page and the full-screen view. - No-jump layout: every frame — including "No frame" — reserves the same footprint (rail + mat as CSS vars), so switching never reflows the page. "No frame" is the bare art floating with a soft shadow. - Full-screen wears a thicker rail + mat so the white border keeps its proportion at large size; "No frame" still maximizes there. - Frame chips redesigned as beveled beads with a clean offset selection ring. - Subtle fading hairline divider between the title and the artwork. Co-Authored-By: Claude Opus 4.8 --- frontend/src/routes/art/+page.svelte | 113 ++++++++++++++++++--------- 1 file changed, 78 insertions(+), 35 deletions(-) diff --git a/frontend/src/routes/art/+page.svelte b/frontend/src/routes/art/+page.svelte index 535083a..de141be 100644 --- a/frontend/src/routes/art/+page.svelte +++ b/frontend/src/routes/art/+page.svelte @@ -15,6 +15,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 who = $derived( art ? [art.artist || 'Unknown artist', art.date_text].filter(Boolean) : [] @@ -24,7 +25,9 @@ try { const saved = localStorage.getItem('ub_art_frame'); if (saved && FRAMES.some((f) => f.id === saved)) frame = saved; - } catch { /* private mode — default frame is fine */ } + const t = parseFloat(localStorage.getItem('ub_art_thickness')); + if (t >= 0.7 && t <= 1.5) thickness = t; + } catch { /* private mode — defaults are fine */ } try { art = await getJSON('/api/art/today'); state = art?.image_url ? 'ready' : 'empty'; @@ -37,6 +40,10 @@ frame = id; try { localStorage.setItem('ub_art_frame', id); } catch { /* ignore */ } } + + function saveThickness() { + try { localStorage.setItem('ub_art_thickness', String(thickness)); } catch { /* ignore */ } + } @@ -68,10 +75,12 @@

Daily Art

A masterwork a day, from the world's open collections.

+ {#if state === 'ready'}
- {/each} + {#if frame !== 'none'} +
+ Thickness + +
+ {/if}
{:else if state === 'empty'} @@ -118,7 +134,7 @@ {#if zoom && art}