refactor(settings): one header, one action row, one integration card

The sweep that follows from the primitives. Nothing here is new behaviour;
every change removes a second way of saying something the surface already
said one way somewhere else.

Headers. The two collapsible security cards stop rebuilding
`SettingsCardHeader` by hand to carry a chevron — the chevron rides inside
the title button, and the description moves out of the collapsed region, so
the first paint is no longer a bare title. The import card shell, the export
and import section headings, and the four free-standing group headers stop
inventing their own type scale: a heading above a GROUP of cards is
`SectionHeading` (`text-base`), a card title is `SettingsCardHeader`
(`text-lg`), and the step between them is what says which is which. The
targets card gets a title instead of a naked icon.

Actions. Every card-level row is `SettingsCardActions`. The primary action
comes out of the header's status slot in six cards (password, web push,
pillar order, coach memory, and the two danger-zone triggers) and out of the
middle of the card in three more; the reset that hung in the dashboard-layout
header joins save as a secondary in the same row. Result and status lines
move ABOVE the row — sources' cross-link, the invite form's two status lines
— because nothing follows a card's actions. Revoking a share link is
`variant="destructive"` rather than an `outline` hand-tinted red in two
different ways. The import row had four variants for four buttons; it has
two. Export downloads are the card's primary, not an outline link.

Integrations. One description sentence with the setup-guide link inline: the
second paragraph was byte-identical across six of eight cards, which is the
tell that it said nothing about the provider it sat under. The `<hr>` under
the header — which existed only in this folder — is gone. So is the hint that
pointed at a guide 40 px above it, and the second format for "not
configured". Connect is one button everywhere: primary, `sm`, in the action
row, instead of primary-and-small in three cards and outline-and-large in
four.

Plus the standards leftovers the audit listed: two `pl-5` list gutters, one
`scroll-mt-20` anchor, a purple header icon, `text-[10px]` badges, four
hand-rolled callout shells that `SettingsInfoTile` already paints, and the
two inline buttons that never had the mobile tap floor at all.
This commit is contained in:
Marc-André Bombeck committed 2026-08-07 19:39:11 +02:00
1 parent ce9b2814e6
commit b2e1aa0cde
63 files changed
+720 -760

No files matched your search

@@ -28,7 +28,7 @@ export function PasskeyUpgradeNudge() {
return (
<div className="border-primary/30 bg-primary/5 flex items-start gap-3 rounded-lg border p-4">
<Sparkles className="text-primary mt-0.5 h-5 w-5 shrink-0" />
<Sparkles className="text-muted-foreground mt-0.5 size-5 shrink-0" />
<div className="min-w-0 flex-1">
<p className="text-sm font-medium">
{t("settings.security.passkeyNudge.title")}
@@ -23,6 +23,7 @@ import {
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Badge } from "@/components/ui/badge";
import { SettingsCardActions } from "@/components/settings/_card-actions";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@@ -231,7 +232,7 @@ export function TotpCard({
{/* ── Enable wizard ── */}
{setup && (
<div className="space-y-4">
<ol className="text-muted-foreground list-decimal space-y-3 pl-5 text-sm">
<ol className="text-muted-foreground list-decimal space-y-3 pl-6 text-sm">
<li>{t("settings.security.totp.step1")}</li>
<li>{t("settings.security.totp.step2")}</li>
</ol>
@@ -326,7 +327,7 @@ export function TotpCard({
{freshCodes && (
<div>
<RecoveryCodesPanel codes={freshCodes} />
<div className="mt-3 flex justify-end">
<SettingsCardActions className="mt-3">
<Button
type="button"
variant="outline"
@@ -335,7 +336,7 @@ export function TotpCard({
>
{t("settings.security.recovery.savedIt")}
</Button>
</div>
</SettingsCardActions>
</div>
)}