From fd5ada5c392781764749a7190185dbbba01d1bda Mon Sep 17 00:00:00 2001 From: Train Chen Date: Thu, 11 Jun 2026 19:02:41 +0200 Subject: [PATCH] fix(garden): wrap theme groups in soft planters, stagger card fade-in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Brief: the Thought Garden looked like stickers stacked on a wall — flat-tinted theme banners + same-elevation cards stacked in space, no atmosphere despite the "garden" framing. Three small visual changes, no logic touched: 1. Soft "planter" container. When there's more than one theme, each group sits inside a rounded-3xl sage-tinted container with a subtle border. Cards now feel held by their group, not floating loose. Single-theme view stays plain — nothing to separate from. 2. Drop the hard banner around the theme label. The planter itself is the visual anchor now, so the label can sit inline with a small sprout icon, no background tint or border. Action buttons stay ghost-styled rather than bg-primary/20 chips. 3. Stagger card fade-in (60ms per card, animationFillMode: backwards so cards aren't pre-painted before their delay). Opening the page now feels like cards blooming in sequence rather than all landing at once. Reversible — pure CSS, no data, no logic. Co-Authored-By: Claude Opus 4.7 --- .../journal/ThoughtGardenScreen.tsx | 129 ++++++++++-------- 1 file changed, 75 insertions(+), 54 deletions(-) diff --git a/src/components/journal/ThoughtGardenScreen.tsx b/src/components/journal/ThoughtGardenScreen.tsx index 029a586..467f9cf 100644 --- a/src/components/journal/ThoughtGardenScreen.tsx +++ b/src/components/journal/ThoughtGardenScreen.tsx @@ -331,63 +331,84 @@ export function ThoughtGardenScreen({ onBack, onOpenChatWithContext, onOpenClust ) : ( -
- {groups.map((group, idx) => ( - -
- {groups.length > 1 && ( -
-

- {group.label} - ({group.thoughts.length}) -

-
- - +
+ {groups.map((group) => { + // When there are multiple themes, each group sits in its own soft + // "planter" — a sage-tinted container that visually holds its cards + // together. With a single theme there's nothing to separate from, + // so we skip the wrapper to avoid an empty-looking frame. + const isMulti = groups.length > 1; + return ( + +
+ {isMulti && ( +
+

+ + {group.label} + + ({group.thoughts.length}) + +

+
+ + +
+ )} +
+ {group.thoughts.map((thought, cardIdx) => ( +
+ toggleSelect(thought.id)} + onArchive={() => archiveThought(thought.id)} + onMoveToTheme={(theme) => { + moveThoughtToTheme(thought.id, theme); + toast.success(bilingual({ fr: `Déplacé vers "${theme}"`, en: `Moved to "${theme}"`, es: `Movido a "${theme}"`, ja: `「${theme}」へ移動しました`, 'zh-Hans': `已移到“${theme}”`, 'zh-Hant': `已移到「${theme}」` })); + }} + onLinkToCluster={(clusterId) => handleLinkThought(thought.id, clusterId)} + onCreateAndLink={(title) => handleCreateAndLink(title, thought.id)} + clusters={clusters} + isFr={isFr} + /> +
+ ))}
- )} -
- {group.thoughts.map(thought => ( - toggleSelect(thought.id)} - onArchive={() => archiveThought(thought.id)} - onMoveToTheme={(theme) => { - moveThoughtToTheme(thought.id, theme); - toast.success(bilingual({ fr: `Déplacé vers "${theme}"`, en: `Moved to "${theme}"`, es: `Movido a "${theme}"`, ja: `「${theme}」へ移動しました`, 'zh-Hans': `已移到“${theme}”`, 'zh-Hant': `已移到「${theme}」` })); - }} - onLinkToCluster={(clusterId) => handleLinkThought(thought.id, clusterId)} - onCreateAndLink={(title) => handleCreateAndLink(title, thought.id)} - clusters={clusters} - isFr={isFr} - /> - ))}
-
-
- ))} + + ); + })}
{activeThought && (