fix(settings): raise primary controls to the 44px touch floor

Apply the canonical min-h-11 sm:min-h-9 (and min-w-11 for icon-only
controls) to the primary Settings controls that sat at 32-40 px on
phones: the AI fallback-chain reorder/remove/save/add icons, provider
form save/test/connect actions, coach-memory forget, avatar replace and
remove, section save/cancel/reset CTAs, the export and import action
rows, the About external links, and the thresholds editor row. Collapse
the injection-sites checkbox grid to one column on phones and stack the
password-change grid below lg.
This commit is contained in:
Marc-André Bombeck committed 2026-06-19 21:27:05 +02:00
1 parent 76bc0f2e1f
commit d9393a2148
19 files changed
+71 -16

No files matched your search

@@ -274,6 +274,7 @@ export function AboutMeSection({
type="button"
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
data-testid="settings-about-me-clear"
disabled={!isAuthenticated || save.isPending}
onClick={() =>
@@ -292,6 +293,7 @@ export function AboutMeSection({
<Button
type="button"
size="sm"
className="min-h-11 sm:min-h-9"
data-testid="settings-about-me-save"
disabled={!isAuthenticated || save.isPending || !dirty}
onClick={() => save.mutate(value)}
+18 -3
View File
@@ -269,7 +269,12 @@ export function AboutSection() {
className="mb-4"
/>
<div className="flex flex-col gap-2 pl-7 sm:flex-row sm:flex-wrap">
<Button asChild variant="outline" size="sm">
<Button
asChild
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
>
<a
href={version.repository}
target="_blank"
@@ -280,7 +285,12 @@ export function AboutSection() {
<ExternalLink className="h-3.5 w-3.5" />
</a>
</Button>
<Button asChild variant="outline" size="sm">
<Button
asChild
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
>
<a
href={version.changelog}
target="_blank"
@@ -291,7 +301,12 @@ export function AboutSection() {
<ExternalLink className="h-3.5 w-3.5" />
</a>
</Button>
<Button asChild variant="outline" size="sm">
<Button
asChild
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
>
<a href={version.docs} target="_blank" rel="noopener noreferrer">
<BookOpen className="h-4 w-4" />
{t("settings.about.docs")}
+3 -2
View File
@@ -694,7 +694,7 @@ export function AccountSection() {
</DialogHeader>
<form onSubmit={handleChangePassword} className="space-y-4">
<div className="grid gap-3 sm:grid-cols-3">
<div className="grid gap-3 lg:grid-cols-3">
<div className="space-y-2">
<Label htmlFor="current-password">
{t("settings.currentPassword")}
@@ -1123,6 +1123,7 @@ function AvatarSection() {
/>
<Button
variant="outline"
className="min-h-11 sm:min-h-9"
disabled={busy}
onClick={() => fileInputRef.current?.click()}
>
@@ -1138,7 +1139,7 @@ function AvatarSection() {
{avatarUrl && (
<Button
variant="ghost"
className="text-destructive"
className="text-destructive min-h-11 sm:min-h-9"
disabled={busy}
onClick={() => {
setMsg(null);
+3 -3
View File
@@ -164,7 +164,7 @@ function ResearchModeCard() {
<Button
size="sm"
variant="outline"
className="mt-2"
className="mt-2 min-h-11 sm:min-h-9"
onClick={() => setDialogOpen(true)}
data-slot="settings-research-mode-reprompt-cta"
>
@@ -286,7 +286,7 @@ function DataResetCard() {
variant="destructive"
size="sm"
disabled={deleting}
className="w-full shrink-0 sm:w-auto"
className="min-h-11 w-full shrink-0 sm:min-h-9 sm:w-auto"
>
{deleting ? (
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
@@ -428,7 +428,7 @@ function AccountDeleteCard() {
variant="destructive"
size="sm"
disabled={deleting}
className="w-full shrink-0 sm:w-auto"
className="min-h-11 w-full shrink-0 sm:min-h-9 sm:w-auto"
data-slot="settings-account-delete-trigger"
>
{deleting ? (
@@ -149,6 +149,7 @@ export function AnthropicProviderForm({
<div>
<Button
size="sm"
className="min-h-11 sm:min-h-9"
onClick={() => saveMutation.mutate()}
disabled={saveMutation.isPending}
>
@@ -208,7 +208,7 @@ export function CodexProviderForm({
<Button
variant="outline"
size="sm"
className="text-destructive shrink-0"
className="text-destructive min-h-11 shrink-0 sm:min-h-9"
onClick={handleDisconnect}
disabled={disconnecting}
>
@@ -274,7 +274,7 @@ export function CodexProviderForm({
variant="outline"
onClick={handleConnect}
disabled={devicePolling}
className="w-full sm:w-auto"
className="min-h-11 w-full sm:min-h-9 sm:w-auto"
>
{devicePolling ? (
<Loader2 className="h-4 w-4 animate-spin motion-reduce:animate-none" />
@@ -196,6 +196,7 @@ export function FallbackChainCard({
aria-label={t("settings.ai.providerChain.moveUp")}
disabled={idx === 0}
onClick={() => move(idx, -1)}
className="min-h-11 min-w-11 sm:min-h-9 sm:min-w-9"
>
<ArrowUp className="h-4 w-4" />
</Button>
@@ -206,6 +207,7 @@ export function FallbackChainCard({
aria-label={t("settings.ai.providerChain.moveDown")}
disabled={idx === entries.length - 1}
onClick={() => move(idx, 1)}
className="min-h-11 min-w-11 sm:min-h-9 sm:min-w-9"
>
<ArrowDown className="h-4 w-4" />
</Button>
@@ -214,7 +216,7 @@ export function FallbackChainCard({
size="sm"
variant="outline"
aria-label={t("settings.ai.providerChain.removeFromChain")}
className="text-destructive"
className="text-destructive min-h-11 min-w-11 sm:min-h-9 sm:min-w-9"
onClick={() => remove(idx)}
disabled={entries.length <= 1}
>
@@ -234,6 +236,7 @@ export function FallbackChainCard({
)}
<Button
size="sm"
className="min-h-11 sm:min-h-9"
onClick={() => saveMutation.mutate(entries)}
disabled={saveMutation.isPending || entries.length === 0}
data-testid="ai-fallback-chain-save"
@@ -247,7 +250,11 @@ export function FallbackChainCard({
</Button>
<AlertDialog>
<AlertDialogTrigger asChild>
<Button size="sm" variant="outline">
<Button
size="sm"
variant="outline"
className="min-h-11 sm:min-h-9"
>
<RotateCcw className="h-4 w-4" />
{t("settings.ai.providerChain.resetDefaults")}
</Button>
@@ -308,6 +315,7 @@ function AddProviderControl({
type="button"
size="sm"
variant="outline"
className="min-h-11 sm:min-h-9"
onClick={() => {
if (isProviderType(picked)) onAdd(picked);
}}
@@ -150,6 +150,7 @@ export function LocalProviderForm({
<div>
<Button
size="sm"
className="min-h-11 sm:min-h-9"
onClick={() => saveMutation.mutate()}
disabled={saveMutation.isPending}
>
@@ -186,6 +186,7 @@ export function OpenAIProviderForm({
<div className="flex flex-wrap gap-2">
<Button
size="sm"
className="min-h-11 sm:min-h-9"
onClick={() => saveMutation.mutate()}
disabled={saveMutation.isPending}
>
@@ -198,6 +198,7 @@ export function RuntimeActionsRow({
<Button
size="sm"
variant="outline"
className="min-h-11 sm:min-h-9"
onClick={runTest}
disabled={testing}
data-testid="ai-test-active-provider"
@@ -213,6 +214,7 @@ export function RuntimeActionsRow({
<Button
size="sm"
variant="outline"
className="min-h-11 sm:min-h-9"
onClick={regenerate}
disabled={regen}
>
@@ -154,6 +154,7 @@ export function CoachMemorySection({
type="button"
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
data-testid="settings-coach-memory-forget-all"
disabled={!isAuthenticated || forgetAll.isPending}
>
@@ -245,6 +246,7 @@ export function CoachMemorySection({
type="button"
variant="ghost"
size="sm"
className="min-h-11 sm:min-h-9"
data-testid="settings-coach-memory-forget"
aria-label={t("settings.ai.coachMemory.forgetAria")}
// v1.11.2 — per-id pending: only the row being
@@ -338,6 +338,7 @@ export function CoachPrefsSection({ isAuthenticated }: CoachPrefsSectionProps) {
<Button
type="button"
size="sm"
className="min-h-11 sm:min-h-9"
onClick={() => save.mutate(draft)}
disabled={save.isPending || isLoading}
data-slot="coach-prefs-save"
@@ -80,7 +80,12 @@ export function CycleTrackingCard({
/>
</div>
{enabled ? (
<Button variant="outline" size="sm" asChild>
<Button
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
asChild
>
<Link href="/cycle">{t("settings.cycleTracking.manage")}</Link>
</Button>
) : null}
@@ -337,7 +337,7 @@ export function DashboardLayoutSection({ id }: { id: string }) {
size="sm"
onClick={() => resetMutation.mutate()}
disabled={resetMutation.isPending}
className="self-end sm:self-auto"
className="min-h-11 self-end sm:min-h-9 sm:self-auto"
>
<RotateCcw className="h-3.5 w-3.5" />
{t("dashboard.layoutReset")}
@@ -551,6 +551,7 @@ export function DashboardLayoutSection({ id }: { id: string }) {
<Button
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
onClick={() => setDraft(null)}
disabled={saveMutation.isPending}
>
@@ -558,6 +559,7 @@ export function DashboardLayoutSection({ id }: { id: string }) {
</Button>
<Button
size="sm"
className="min-h-11 sm:min-h-9"
onClick={() => layout && saveMutation.mutate(layout)}
disabled={saveMutation.isPending}
>
@@ -267,6 +267,7 @@ function CsvCard({
data-testid={actionTestId}
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
onClick={handleDownload}
disabled={busy}
>
@@ -354,6 +355,7 @@ function MedicationsCsvCard() {
data-testid="export-action-medications-csv"
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
onClick={handleDownload}
disabled={busy}
>
@@ -443,6 +445,7 @@ function FullBackupCard() {
data-testid="export-action-full-backup"
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
onClick={handleDownload}
disabled={busy}
>
@@ -552,6 +555,7 @@ function CycleExportCard() {
data-testid="export-action-cycle"
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
onClick={handleGenerate}
disabled={busy}
>
+8
View File
@@ -366,6 +366,7 @@ function AppleHealthImportCard() {
type="button"
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
disabled={busy}
onClick={() => fileInputRef.current?.click()}
data-testid="import-action-apple-health"
@@ -615,6 +616,7 @@ function JsonImportCard() {
type="button"
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
onClick={() => fileInputRef.current?.click()}
data-testid="import-json-choose-file"
>
@@ -625,6 +627,7 @@ function JsonImportCard() {
type="button"
variant="ghost"
size="sm"
className="min-h-11 sm:min-h-9"
onClick={downloadExample}
data-testid="import-json-download-example"
>
@@ -634,6 +637,7 @@ function JsonImportCard() {
<Button
type="button"
size="sm"
className="min-h-11 sm:min-h-9"
disabled={busy || text.trim().length === 0}
onClick={handleImport}
data-testid="import-action-json"
@@ -863,6 +867,7 @@ function CsvImportCard() {
type="button"
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
onClick={() => fileInputRef.current?.click()}
data-testid="import-csv-choose-file"
>
@@ -873,6 +878,7 @@ function CsvImportCard() {
type="button"
variant="ghost"
size="sm"
className="min-h-11 sm:min-h-9"
onClick={downloadExample}
data-testid="import-csv-download-example"
>
@@ -883,6 +889,7 @@ function CsvImportCard() {
type="button"
variant="secondary"
size="sm"
className="min-h-11 sm:min-h-9"
disabled={busy || text.trim().length === 0}
onClick={() => void send(true)}
data-testid="import-csv-preview"
@@ -895,6 +902,7 @@ function CsvImportCard() {
<Button
type="button"
size="sm"
className="min-h-11 sm:min-h-9"
disabled={busy || text.trim().length === 0}
onClick={() => void send(false)}
data-testid="import-action-csv"
@@ -72,7 +72,7 @@ export function InjectionSitesCard({
title={t("settings.globalExcludedInjectionSitesLabel")}
description={t("settings.globalExcludedInjectionSitesHint")}
/>
<div className="mt-3 grid grid-cols-2 gap-2 pl-7">
<div className="mt-3 grid grid-cols-1 gap-2 pl-7 sm:grid-cols-2">
{INJECTION_SITE_KEYS.map((site) => (
<label key={site} className="flex items-center gap-2 text-sm">
<Checkbox
@@ -224,7 +224,7 @@ export function InsightsPillOrderSection({ id }: { id?: string }) {
onClick={() => saveMutation.mutate(draftTiles)}
disabled={busy || !dirty}
data-slot="insights-pill-order-save"
className="self-end sm:self-auto"
className="min-h-11 self-end sm:min-h-9 sm:self-auto"
>
{saveMutation.isPending && (
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
@@ -324,6 +324,7 @@ function MetricRow({
onClick={() => valid && onSave({ min: minNum, max: maxNum })}
disabled={busy || !valid}
size="sm"
className="min-h-11 sm:min-h-9"
>
{t("common.save")}
</Button>
@@ -331,6 +332,7 @@ function MetricRow({
<Button
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
onClick={onReset}
disabled={busy}
>