From 89352e71239f18eaa238adc038c122d5bc4c7428 Mon Sep 17 00:00:00 2001 From: jay Date: Mon, 22 Jun 2026 10:58:55 -0400 Subject: [PATCH] home3: small-joys rail -> rotating two-up shelf (option A: label + dots + arrows) Two jewel cards at a time, reader-advanced (no auto-motion); 3 cells total, wraps. Keeps each card at generous size instead of cramming three. Co-Authored-By: Claude Opus 4.8 --- frontend/src/routes/home3/+page.svelte | 101 ++++++++++++++++++------- 1 file changed, 74 insertions(+), 27 deletions(-) diff --git a/frontend/src/routes/home3/+page.svelte b/frontend/src/routes/home3/+page.svelte index 28a2889..e385398 100644 --- a/frontend/src/routes/home3/+page.svelte +++ b/frontend/src/routes/home3/+page.svelte @@ -17,6 +17,12 @@ } let headline = $derived(clampWords(news?.title ?? 'What went right this week: the good news that actually matters')); + // small-joys shelf: 3 cells shown two at a time, rotated by the reader (no auto-motion) + const JOY_ACCENTS = ['#D2861B', '#8857C2', '#3F9A66']; + let joyIdx = $state(0); + const prevJoy = () => (joyIdx = (joyIdx + 2) % 3); + const nextJoy = () => (joyIdx = (joyIdx + 1) % 3); + onMount(async () => { try { const a = await getJSON('/api/art/today'); @@ -42,6 +48,40 @@ +{#snippet joyCard(i)} + {#if i === 0} +
+ +
+
Word of the day
+

Serene adj.

+

/səˈriːn/

+

Calm, peaceful, and untroubled. The quiet after a storm passes.

+
+
+ {:else if i === 1} +
+ +
+
Quote of the day
+

Very little is needed to make a happy life.

+
Marcus Aurelius
+
+
+ {:else} +
+
+
+
A good thing today
+ SOON +
+

1928 ON THIS DAY

+

Penicillin was discovered by a happy accident.

+
+
+ {/if} +{/snippet} + - -
-
- -
-
Word of the day
-

Serene adj.

-

/səˈriːn/

-

Calm, peaceful, and untroubled. The quiet after a storm passes.

-
-
-
- -
-
Quote of the day
-

Very little is needed to make a happy life.

-
Marcus Aurelius
-
-
-
-
-
-
A good thing today
- SOON + +
+
+
Small joys for today· {joyIdx + 1} of 3
+
+ +
+ +
-

1928 ON THIS DAY

-

Penicillin was discovered by a happy accident.

+
+ {@render joyCard(joyIdx)} + {@render joyCard((joyIdx + 1) % 3)} +
@@ -327,7 +358,23 @@ /* "small joys" rail — little jewels: one big focal point per card, a faint oversized watermark glyph, an accent-tag label, soft diagonal gradient + long low shadow. */ - .joys { flex: none; display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; } + .joys-shelf { flex: none; } + .joys-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; } + .joys-title { display: flex; align-items: baseline; gap: 8px; } + .jt-label { font-family: 'Newsreader', Georgia, serif; font-style: italic; font-size: 17px; color: #7a6f5b; } + .jt-count { font-size: 12px; color: #b3a890; } + .joys-nav { display: flex; align-items: center; gap: 14px; } + .joys-dots { display: flex; align-items: center; gap: 6px; } + .dot { width: 6px; height: 6px; border-radius: 50%; background: #d9cdb8; transition: width 0.2s ease, background 0.2s ease; } + .dot.on { width: 18px; border-radius: 3px; } + .joys-arrows { display: flex; gap: 8px; } + .arrow { + width: 30px; height: 30px; border-radius: 50%; border: 1px solid #e0d3b8; background: transparent; + color: #b09a6e; font-size: 14px; cursor: pointer; display: flex; align-items: center; justify-content: center; + padding: 0; line-height: 1; transition: background 0.15s ease, color 0.15s ease; + } + .arrow:hover { background: #fff; color: #9a7b3e; } + .joys { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } .joy { position: relative; overflow: hidden; border-radius: 20px; padding: 22px 24px; } .joy-in { position: relative; } /* content sits above the watermark */ .wm { position: absolute; font-family: 'Newsreader', Georgia, serif; line-height: 1; pointer-events: none; }