From 6657e3da6fd01a4037b8c3a56cef405c115653cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Fri, 5 Jun 2026 00:58:39 +0200 Subject: [PATCH] fix(ui): elevate the capture FAB and unify selectable-control and export-card styling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lift the bottom-bar center capture action into a proper floating-action button: a 56px target raised out of the bar with a card collar ring and a stronger shadow, so it reads as the primary CTA rather than a fifth flush tab. Desktop sidebar nav is unaffected. Unify the selectable controls across the mood logging surface onto one design language: the 5 mood faces, the tag tiles, the rated-factor steps and the GLP-1 chips now share a single selected-state treatment (border-primary, bg-primary/15, primary text, single border) and a consistent rounding family. Match the More-hub row height to the capture tiles so equivalent tappable rows share one min-height at the same tier. Give the demoted doctor-report export card a primary-tinted icon to match its peer cards — the demotion comes from position and size, not a muted icon. Drop the doubled heading atop the mood sheet by demoting the hero question to a field label so the sheet title is the single primary heading. Reword the capture mood option description to describe the action instead of echoing the hero question. (cherry picked from commit 1296f151f1c9a7c95ff917e3d69a5c0d369ba210) --- messages/de.json | 2 +- messages/en.json | 2 +- messages/es.json | 2 +- messages/fr.json | 2 +- messages/it.json | 2 +- messages/pl.json | 2 +- .../layout/__tests__/bottom-nav.test.tsx | 21 +++++++++++++++---- src/components/layout/bottom-nav.tsx | 18 +++++++++++----- src/components/mood/mood-form.tsx | 15 +++++++++++-- src/components/mood/mood-tag-picker.tsx | 5 ++++- .../settings/arztbericht-hero-card.tsx | 2 +- 11 files changed, 54 insertions(+), 19 deletions(-) diff --git a/messages/de.json b/messages/de.json index d33c982f9..56424d29e 100644 --- a/messages/de.json +++ b/messages/de.json @@ -215,7 +215,7 @@ "medication": "Medikament", "medicationDescription": "Eine Dosis als genommen markieren", "mood": "Stimmung", - "moodDescription": "Wie geht es dir?" + "moodDescription": "Stimmung und Tags erfassen" } }, "auth": { diff --git a/messages/en.json b/messages/en.json index c25d5bbdc..15d380056 100644 --- a/messages/en.json +++ b/messages/en.json @@ -215,7 +215,7 @@ "medication": "Medication", "medicationDescription": "Mark a dose as taken", "mood": "Mood", - "moodDescription": "How are you feeling?" + "moodDescription": "Log your mood and tags" } }, "auth": { diff --git a/messages/es.json b/messages/es.json index ff88480e4..1949ec493 100644 --- a/messages/es.json +++ b/messages/es.json @@ -215,7 +215,7 @@ "medication": "Medicamento", "medicationDescription": "Marcar una dosis como tomada", "mood": "Estado de ánimo", - "moodDescription": "¿Cómo te sientes?" + "moodDescription": "Registrar estado de ánimo y etiquetas" } }, "auth": { diff --git a/messages/fr.json b/messages/fr.json index 1bd7ac9f3..b9d7892d7 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -215,7 +215,7 @@ "medication": "Médicament", "medicationDescription": "Marquer une dose comme prise", "mood": "Humeur", - "moodDescription": "Comment vous sentez-vous ?" + "moodDescription": "Enregistrer l'humeur et les tags" } }, "auth": { diff --git a/messages/it.json b/messages/it.json index 7db624f22..ec384b607 100644 --- a/messages/it.json +++ b/messages/it.json @@ -215,7 +215,7 @@ "medication": "Farmaco", "medicationDescription": "Segna una dose come assunta", "mood": "Umore", - "moodDescription": "Come ti senti?" + "moodDescription": "Registra umore e tag" } }, "auth": { diff --git a/messages/pl.json b/messages/pl.json index c86de40e0..b0e1982b5 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -215,7 +215,7 @@ "medication": "Lek", "medicationDescription": "Oznacz dawkę jako przyjętą", "mood": "Nastrój", - "moodDescription": "Jak się czujesz?" + "moodDescription": "Zapisz nastrój i tagi" } }, "auth": { diff --git a/src/components/layout/__tests__/bottom-nav.test.tsx b/src/components/layout/__tests__/bottom-nav.test.tsx index 3889f6f11..1f64665c2 100644 --- a/src/components/layout/__tests__/bottom-nav.test.tsx +++ b/src/components/layout/__tests__/bottom-nav.test.tsx @@ -75,11 +75,24 @@ describe(" iOS-parity layout", () => { it("each strip entry meets the 44 px tap-target floor (min-h-11 min-w-11)", () => { const html = render(); - // Five flanking strip slots (Home, Meds, capture button, Insights, - // More) all carry `min-h-11 min-w-11`. We don't hard-pin the count - // because a future entry would also satisfy the contract. + // The four flanking strip slots (Home, Meds, Insights, More) carry + // `min-h-11 min-w-11`. We don't hard-pin the count because a future + // entry would also satisfy the contract. const matches = html.match(/min-h-11 min-w-11/g) ?? []; - expect(matches.length).toBeGreaterThanOrEqual(5); + expect(matches.length).toBeGreaterThanOrEqual(4); + }); + + it("the center capture FAB is a larger, elevated tap target", () => { + const html = render(); + // The FAB clears the 44px floor with a 56px (h-14 w-14) target and + // is lifted out of the bar (negative top margin + card ring + raised + // shadow) so it reads as the primary CTA, not a flush fifth tab. + const capture = html.match(/]*bottom-nav-capture[^>]*>/); + expect(capture).not.toBeNull(); + expect(capture![0]).toMatch(/h-14 w-14/); + expect(capture![0]).toMatch(/-mt-5/); + expect(capture![0]).toMatch(/ring-4/); + expect(capture![0]).toMatch(/shadow-lg/); }); it("no longer lists the deprecated /targets entry (v1.8.6)", () => { diff --git a/src/components/layout/bottom-nav.tsx b/src/components/layout/bottom-nav.tsx index a90d9637a..415ac897f 100644 --- a/src/components/layout/bottom-nav.tsx +++ b/src/components/layout/bottom-nav.tsx @@ -128,8 +128,13 @@ export function BottomNav() { {PRIMARY_LEFT.map(renderPrimary)} {/* Center capture action — a labeled button (NOT a link) that - opens the capture picker. Visually elevated so it reads as - the primary CTA. */} + opens the capture picker. Elevated as a Floating-Action- + Button: it sits larger than the flanking tabs (h-14 = 56px, + well above the 44px tap-target floor), lifts above the bar + with a negative top margin, and carries a filled-primary + collar (a `bg-card` ring that punches it out of the bar) plus + a stronger shadow so it reads as the bar's primary CTA rather + than a fifth flush tab. */}
@@ -193,8 +198,11 @@ export function BottomNav() { href={item.href} onClick={() => setMoreOpen(false)} aria-current={isActive ? "page" : undefined} + // v1.12 — `min-h-14` matches the capture-picker tiles so + // the equivalent tappable rows share one height at this + // tier (and the larger row is a more comfortable target). className={cn( - "border-border flex min-h-11 items-center gap-3 rounded-lg border px-4 py-3 transition-colors", + "border-border flex min-h-14 items-center gap-3 rounded-lg border px-4 py-3 transition-colors", isActive ? "text-primary bg-primary/5" : "text-foreground hover:bg-accent/40", diff --git a/src/components/mood/mood-form.tsx b/src/components/mood/mood-form.tsx index 44ca476e1..ed63cf8f2 100644 --- a/src/components/mood/mood-form.tsx +++ b/src/components/mood/mood-form.tsx @@ -275,7 +275,14 @@ export function MoodForm({ onSuccess, onCancel, footerSlot }: MoodFormProps) { radiogroup (best-on-the-left order); tapping one picks the mood and reveals the annotate panel below. */}
-