refactor(settings): unify card headers, integration verbs, test buttons, and tap targets

Holistic consistency pass over the settings and integration surfaces so the
same concept reads and behaves the same way everywhere.

- Card headers: migrate the four integration cards (Withings, WHOOP,
  Fitbit/Google Health, Mood Log) plus the profile, passkeys, avatar, about,
  api-endpoints, api-tokens, and sharing cards onto the shared
  SettingsCardHeader primitive. Extend the primitive with an inline title
  accessory slot (Fitbit tag + experimental badge) and a multi-line
  description slot (overlap / experimental / deprecation sub-notes), keeping
  the rendered result identical.
- Integration verbs: normalise Mood Log onto the canonical "Sync now" /
  "Sync all data" / "Synchronize" set used by the other integrations, across
  all six locales. Swap the full-sync icon from Download to RefreshCw and
  align its action-row icon metrics with the sibling cards.
- Test buttons: migrate Telegram and ntfy off their hand-rolled "Test
  message" buttons onto the shared TestConnectionButton, so every channel and
  integration test control shares one icon, label, latency readout, and error
  taxonomy. Retire the now-unused testMessage / testSent strings.
- ntfy auth-token placeholder no longer reuses the "Saved" status string;
  it now reads "Saved — enter new to replace" like the other secret fields.
- Save-success copy: collapse the moodLog and Telegram bespoke strings onto
  the shared settings.saved string.
- Tap targets: floor every size="sm" action-row button (sync / full-sync /
  test / disconnect / save / connect-secret copy) at min-h-11, fixed at the
  TestConnectionButton source and across the cards, so they clear the 44px
  touch minimum.
- Contrast: the onboarding source-card badge moves from muted-on-muted to
  text-foreground; web-push card body rhythm aligns on space-y-4; Mood Log's
  deprecation note drops its bespoke 11px-italic treatment for the shared
  sub-note style.

(cherry picked from commit 11931d14b7875b7e2184a3b373d7a34b842f8eae)
This commit is contained in:
Marc-André Bombeck committed 2026-06-05 03:45:04 +02:00
1 parent b64f48bce3
commit 3ce0b69802
17 files changed
+248 -279

No files matched your search

+26 -31
View File
@@ -19,6 +19,7 @@ import {
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { SettingsCardHeader } from "@/components/settings/_card-header";
import { useAuth } from "@/hooks/use-auth";
import { formatDate, formatDateTime } from "@/lib/format";
import { useTranslations } from "@/lib/i18n/context";
@@ -77,15 +78,11 @@ function ApiEndpointsCard() {
return (
<div className="bg-card border-border rounded-xl border p-6">
<div className="flex items-center gap-2">
<Key className="text-primary h-5 w-5" />
<h2 className="text-lg font-semibold">
{t("settings.apiEndpointsTitle")}
</h2>
</div>
<p className="text-muted-foreground mt-1 text-xs">
{t("settings.apiEndpointsDescription")}
</p>
<SettingsCardHeader
icon={Key}
title={t("settings.apiEndpointsTitle")}
description={t("settings.apiEndpointsDescription")}
/>
{/* Desktop table — verbatim layout for md+. */}
<div className="border-border mt-4 hidden overflow-x-auto rounded-lg border md:block">
@@ -244,28 +241,26 @@ function ApiTokensCard() {
return (
<div className="bg-card border-border rounded-xl border p-6">
<div className="flex flex-wrap items-start justify-between gap-2">
<div className="flex items-center gap-2">
<Key className="text-primary h-5 w-5" />
<h2 className="text-lg font-semibold">{t("settings.apiTokens")}</h2>
</div>
<div className="flex flex-wrap items-center gap-2">
{activeTokens.length > 0 && (
<Badge className="border-dracula-green/30 bg-dracula-green/15 text-dracula-green">
{t("settings.configured")}
</Badge>
)}
{latestActiveUse && (
<Badge variant="outline" className="text-xs">
{t("settings.tokenTableLastUsed")}:{" "}
{formatDateTime(latestActiveUse)}
</Badge>
)}
</div>
</div>
<p className="text-muted-foreground mt-1 text-xs">
{t("settings.apiTokensDescription")}
</p>
<SettingsCardHeader
icon={Key}
title={t("settings.apiTokens")}
description={t("settings.apiTokensDescription")}
status={
<>
{activeTokens.length > 0 && (
<Badge className="border-dracula-green/30 bg-dracula-green/15 text-dracula-green">
{t("settings.configured")}
</Badge>
)}
{latestActiveUse && (
<Badge variant="outline" className="text-xs">
{t("settings.tokenTableLastUsed")}:{" "}
{formatDateTime(latestActiveUse)}
</Badge>
)}
</>
}
/>
<div className="mt-4 space-y-4">
<form onSubmit={handleCreate} className="flex gap-2">