chore(ui): apply M7 + L1 + L3 + L4 polish across medication form, motion-reduce, details aria, therapy timeline

W10 design-review carry-over items. M7 lifts the medication-form
day-of-week buttons, the more-horizontal trigger, and the schedule
label-input gaps to the 44 px / space-y-2 standard used by every
other settings surface. L1 pairs every animate-spin/pulse/bounce
with motion-reduce:animate-none across the component tree so users
with prefers-reduced-motion get a still surface. L3 adds the
aria-controls + panel-id pairing to the inventory + coach-evidence
<details> blocks for parity with the Health Score provenance
accordion. L4 inserts a sr-only h4 per therapy-timeline entry so
screen-reader users can jump between medication blocks.
This commit is contained in:
Marc-André Bombeck committed 2026-05-15 17:13:42 +02:00
1 parent 19b5129306
commit 32a023dfff
71 files changed
+165 -136

No files matched your search

+1 -1
View File
@@ -75,7 +75,7 @@ export function AiQualitySection() {
if (query.isLoading) {
return (
<div className="bg-card border-border flex items-center gap-2 rounded-xl border p-6">
<Loader2 className="h-4 w-4 animate-spin" />
<Loader2 className="h-4 w-4 animate-spin motion-reduce:animate-none" />
<span className="text-muted-foreground text-sm">
{t("admin.aiQuality.loading")}
</span>
@@ -170,7 +170,7 @@ export function ApiTokenOverviewSection() {
) : !tokens?.length ? (
// v1.4.15 phase-C5: empty state explains where tokens come
// from (native client sign-in / Settings → Account) so a
// fresh admin doesn't think they need to create them here.
// fresh admin doesn motion-reduce:animate-none't think they need to create them here.
<EmptyState
icon={<Key className="size-6" />}
title={t("admin.tokensEmptyTitle")}
@@ -133,7 +133,7 @@ export function AppLogPreviewSection() {
aria-label={t("admin.section.app-logs.refresh")}
>
<RefreshCw
className={`h-4 w-4 ${isFetching ? "animate-spin" : ""}`}
className={`h-4 w-4 ${isFetching ? "animate-spin" : ""} motion-reduce:animate-none`}
/>
</Button>
</header>
@@ -195,7 +195,7 @@ export function AppLogPreviewSection() {
{isLoading ? (
<div className="flex justify-center py-4">
<Loader2 className="text-muted-foreground h-5 w-5 animate-spin" />
<Loader2 className="text-muted-foreground h-5 w-5 animate-spin motion-reduce:animate-none" />
</div>
) : events.length === 0 ? (
<EmptyState
+1 -1
View File
@@ -90,7 +90,7 @@ function RestoreRowDialog({
className="min-h-11"
>
{pending ? (
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
) : (
<History className="mr-1 h-3.5 w-3.5" />
)}
+1 -1
View File
@@ -119,7 +119,7 @@ export function BugReportSection() {
disabled={updateSettings.isPending}
>
{updateSettings.isPending && (
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
)}
{t("common.save")}
</Button>
@@ -99,7 +99,7 @@ export function CoachFeedbackSection() {
{query.isLoading ? (
<div className="flex items-center gap-2">
<Loader2 className="h-4 w-4 animate-spin" />
<Loader2 className="h-4 w-4 animate-spin motion-reduce:animate-none" />
<span className="text-muted-foreground text-sm">
{t("admin.coachFeedback.loading")}
</span>
+1 -1
View File
@@ -85,7 +85,7 @@ export function DangerZoneSection() {
disabled={wipeAllData.isPending}
>
{wipeAllData.isPending ? (
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
) : (
<Trash2 className="mr-1 h-3.5 w-3.5" />
)}
@@ -104,7 +104,7 @@ export function FeedbackInboxSection() {
<TabsContent key={s} value={s} className="mt-4">
{isLoading ? (
<div className="flex items-center gap-2">
<Loader2 className="text-muted-foreground h-4 w-4 animate-spin" />
<Loader2 className="text-muted-foreground h-4 w-4 animate-spin motion-reduce:animate-none" />
<span className="text-muted-foreground text-sm">
{t("admin.feedback.loading")}
</span>
@@ -435,7 +435,7 @@ function FeedbackDetailDialog({
onClick={() => update.mutate({ adminNote: note || null })}
>
{update.isPending && (
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
)}
{t("admin.feedback.saveNote")}
</Button>
@@ -497,7 +497,7 @@ function FeedbackDetailDialog({
className="ml-auto"
>
{publish.isPending ? (
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
) : (
<GitPullRequest className="mr-1.5 h-3.5 w-3.5" />
)}
+2 -2
View File
@@ -148,7 +148,7 @@ export function GlitchtipSection() {
disabled={testGlitchtip.isPending || updateSettings.isPending}
>
{testGlitchtip.isPending && (
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
)}
{t("common.test")}
</Button>
@@ -158,7 +158,7 @@ export function GlitchtipSection() {
disabled={updateSettings.isPending}
>
{updateSettings.isPending && (
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
)}
{t("common.save")}
</Button>
@@ -340,7 +340,7 @@ export function LoginOverviewSection() {
{isLoading ? (
<div className="flex justify-center py-4">
<Loader2 className="text-muted-foreground h-5 w-5 animate-spin" />
<Loader2 className="text-muted-foreground h-5 w-5 animate-spin motion-reduce:animate-none" />
</div>
) : !entries.length ? (
<EmptyState
@@ -79,7 +79,7 @@ export function RecentAuditPreview() {
{isLoading ? (
<div className="flex items-center gap-2 py-2">
<Loader2
className="text-muted-foreground h-4 w-4 animate-spin"
className="text-muted-foreground h-4 w-4 animate-spin motion-reduce:animate-none"
aria-hidden="true"
/>
<span className="text-muted-foreground text-sm">
+3 -3
View File
@@ -177,7 +177,7 @@ export function RemindersSection() {
disabled={testNotification.isPending}
>
{testNotification.isPending && (
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
)}
<Bell className="mr-1.5 h-3.5 w-3.5" />
{t("admin.notificationTestSend")}
@@ -189,7 +189,7 @@ export function RemindersSection() {
disabled={reminderCheck.isPending}
>
{reminderCheck.isPending && (
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
)}
<Activity className="mr-1.5 h-3.5 w-3.5" />
{t("admin.reminderCheckRun")}
@@ -220,7 +220,7 @@ export function RemindersSection() {
}
>
{updateSettings.isPending && (
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
)}
{t("common.save")}
</Button>
@@ -127,7 +127,7 @@ export function SystemStatusSummary() {
) : (
<div className="mt-4 flex items-center gap-2">
<Loader2
className="text-muted-foreground h-4 w-4 animate-spin"
className="text-muted-foreground h-4 w-4 animate-spin motion-reduce:animate-none"
aria-hidden="true"
/>
<span className="text-muted-foreground text-sm">
+2 -2
View File
@@ -149,7 +149,7 @@ export function UmamiSection() {
disabled={testUmami.isPending || updateSettings.isPending}
>
{testUmami.isPending && (
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
)}
{t("common.test")}
</Button>
@@ -159,7 +159,7 @@ export function UmamiSection() {
disabled={updateSettings.isPending}
>
{updateSettings.isPending && (
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
)}
{t("common.save")}
</Button>
@@ -407,7 +407,7 @@ export function UserManagementSection() {
)
) : (
<div className="mt-4 flex items-center gap-2">
<Loader2 className="text-muted-foreground h-4 w-4 animate-spin" />
<Loader2 className="text-muted-foreground h-4 w-4 animate-spin motion-reduce:animate-none" />
<span className="text-muted-foreground text-sm">
{t("admin.loadingUsers")}
</span>
@@ -460,7 +460,7 @@ export function UserManagementSection() {
}
>
{updateUser.isPending && (
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
)}
{t("common.save")}
</Button>
@@ -510,7 +510,7 @@ export function UserManagementSection() {
}
>
{resetPw.isPending && (
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
)}
{t("admin.reset")}
</Button>
@@ -562,7 +562,7 @@ export function UserManagementSection() {
className="bg-destructive hover:bg-destructive/90"
>
{forceLogout.isPending ? (
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
) : null}
{t("admin.section.users.forceLogout")}
</AlertDialogAction>
@@ -135,7 +135,7 @@ export function WebPushVapidSection() {
disabled={updateSettings.isPending}
>
{updateSettings.isPending && (
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
)}
{t("common.save")}
</Button>