fix(settings): keep note and paste fields at 16 px on a phone

On /settings/anamnesis the four note fields were raw textareas styled
by three copies of a class constant with text-sm (14 px), and on
/settings/export the three paste fields used text-xs (12 px) and the
backup passphrase text-sm. iOS zooms the page into such a field on
focus and leaves it zoomed. The notes use the Textarea primitive now
and the export fields keep the small size only under a fine pointer.

The 16 px guard read the five field primitives and could not see a
call site override their size, or a raw field styled from a constant.
It now parses every field call site; four that are still small sit on
a list that only shrinks. The focus guard drops the three records
files, whose fields come from the primitive now.
This commit is contained in:
Marc-André Bombeck committed 2026-11-11 21:43:10 +01:00
1 parent 2a60f21a8b
commit 3a249bccba
9 files changed
+193 -28

No files matched your search

@@ -37,6 +37,7 @@ import { SettingsCardActions } from "@/components/settings/_card-actions";
import { QueryErrorRow } from "@/components/ui/query-error-row";
import { SettingsInfoTile } from "@/components/settings/_info-tile";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { ConfirmButton } from "@/components/ui/confirm-button";
import {
useAboutMeSaveTimeoutMs,
@@ -44,7 +45,6 @@ import {
} from "@/hooks/use-ai-capability";
import { useTranslations } from "@/lib/i18n/context";
import { queryKeys } from "@/lib/query-keys";
import { cn } from "@/lib/utils";
import { apiGet, apiPut } from "@/lib/api/api-fetch";
import { withBaseToken, isConflict } from "@/lib/api/optimistic-token";
@@ -61,9 +61,6 @@ interface AboutMeData {
fieldMaxChars: number;
}
const FIELD_CLASSES =
"border-input bg-background placeholder:text-muted-foreground focus-visible:border-input-focus w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none";
export function AboutMeNoteManager() {
const { t } = useTranslations();
const queryClient = useQueryClient();
@@ -134,10 +131,11 @@ export function AboutMeNoteManager() {
<Label htmlFor="settings-about-me-freetext">
{t("settings.ai.aboutMe.freeTextLabel")}
</Label>
<textarea
<Textarea
id="settings-about-me-freetext"
data-testid="settings-about-me-textarea"
className={cn(FIELD_CLASSES, "min-h-36 resize-y")}
className="resize-y"
rows={6}
value={value}
maxLength={maxChars}
placeholder={t("settings.ai.aboutMe.placeholder")}
@@ -31,10 +31,10 @@ import { Button } from "@/components/ui/button";
import { SettingsCardActions } from "@/components/settings/_card-actions";
import { QueryErrorRow } from "@/components/ui/query-error-row";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { FreeTextTakeOver } from "@/components/records/free-text-take-over";
import { useTranslations } from "@/lib/i18n/context";
import { queryKeys } from "@/lib/query-keys";
import { cn } from "@/lib/utils";
import { apiGet, apiPut } from "@/lib/api/api-fetch";
import { useAboutMeSaveTimeoutMs } from "@/hooks/use-ai-capability";
import { withBaseToken, isConflict } from "@/lib/api/optimistic-token";
@@ -50,9 +50,6 @@ interface AboutMeData {
fieldMaxChars: number;
}
const FIELD_CLASSES =
"border-input bg-background placeholder:text-muted-foreground focus-visible:border-input-focus w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none";
export function AllergyFreeTextNote({
leadingAction,
}: {
@@ -122,10 +119,10 @@ export function AllergyFreeTextNote({
<p className="text-muted-foreground text-xs">
{t("records.allergies.freeText.hint")}
</p>
<textarea
<Textarea
id="records-allergy-free-text"
data-testid="records-allergy-free-text"
className={cn(FIELD_CLASSES, "min-h-16 resize-y")}
className="resize-y"
rows={2}
value={value}
maxLength={fieldMaxChars}
@@ -29,11 +29,11 @@ import { showErrorToast } from "@/lib/errors/error-toast";
import { Button } from "@/components/ui/button";
import { SettingsCardActions } from "@/components/settings/_card-actions";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { FreeTextTakeOver } from "@/components/records/free-text-take-over";
import { QueryErrorCard } from "@/components/ui/query-error-card";
import { useTranslations } from "@/lib/i18n/context";
import { queryKeys } from "@/lib/query-keys";
import { cn } from "@/lib/utils";
import { apiGet, apiPut } from "@/lib/api/api-fetch";
import { useAboutMeSaveTimeoutMs } from "@/hooks/use-ai-capability";
@@ -47,9 +47,6 @@ interface AboutMeData {
fieldMaxChars: number;
}
const FIELD_CLASSES =
"border-input bg-background placeholder:text-muted-foreground focus-visible:border-input-focus w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none";
export function ConditionsManager() {
const { t } = useTranslations();
const queryClient = useQueryClient();
@@ -112,10 +109,10 @@ export function ConditionsManager() {
return (
<div className="space-y-1.5">
<Label htmlFor={`records-conditions-${key}`}>{label}</Label>
<textarea
<Textarea
id={`records-conditions-${key}`}
data-testid={`records-conditions-${key}`}
className={cn(FIELD_CLASSES, "min-h-16 resize-y")}
className="resize-y"
rows={2}
value={value[key]}
maxLength={fieldMaxChars}
+1 -1
View File
@@ -566,7 +566,7 @@ function FullBackupCard() {
data-lpignore="true"
data-1p-ignore="true"
data-bwignore="true"
className="h-9 text-sm"
className="h-9"
/>
<p className="text-muted-foreground text-xs">
{t("settings.sections.export.cards.fullBackup.passphraseHelp")}
@@ -130,7 +130,7 @@ export function CsvImportCard() {
maxLength={MAX_PASTE_CHARS}
spellCheck={false}
placeholder="type,value,unit,measuredAt,…"
className="font-mono text-xs"
className="font-mono sm:pointer-fine:text-xs"
/>
<p className="text-muted-foreground text-right text-xs tabular-nums">
{t("settings.sections.export.import.charCount", {
@@ -234,7 +234,7 @@ export function DoseHistoryImportCard() {
maxLength={MAX_PASTE_CHARS}
spellCheck={false}
placeholder="Date,Scheduled Date,Medication,…"
className="font-mono text-xs"
className="font-mono sm:pointer-fine:text-xs"
/>
<p className="text-muted-foreground text-right text-xs tabular-nums">
{t("settings.sections.export.import.charCount", {
@@ -211,7 +211,7 @@ export function JsonImportCard() {
maxLength={MAX_PASTE_CHARS}
spellCheck={false}
placeholder='{"measurements":[…],"moodEntries":[…]}'
className="font-mono text-xs"
className="font-mono sm:pointer-fine:text-xs"
/>
<p className="text-muted-foreground text-right text-xs tabular-nums">
{t("settings.sections.export.import.charCount", {