From 8d60690b4ab9aa2cc59ce7f0e5d59bfdf0477635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 24 Sep 2026 12:18:24 +0200 Subject: [PATCH] fix(insights): give the setup hint's dismiss button a 44 px target on phones --- .../__tests__/ai-setup-hint-target.test.tsx | 48 +++++++++++++++++++ src/components/insights/ai-setup-hint.tsx | 4 +- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/components/insights/__tests__/ai-setup-hint-target.test.tsx diff --git a/src/components/insights/__tests__/ai-setup-hint-target.test.tsx b/src/components/insights/__tests__/ai-setup-hint-target.test.tsx new file mode 100644 index 000000000..6e06357f6 --- /dev/null +++ b/src/components/insights/__tests__/ai-setup-hint-target.test.tsx @@ -0,0 +1,48 @@ +/** + * The overview's setup hint closes with an icon button in its header. On a + * phone it is the only control on the tile a thumb has to hit, so it carries + * the 44 px floor every other mobile action does (`size-11`), stepping down + * from `sm` like the rest of the app. + */ +import { renderToStaticMarkup } from "react-dom/server"; +import { describe, expect, it, vi } from "vitest"; + +vi.mock("@/hooks/use-auth", () => ({ + useAuth: () => ({ user: { id: "u1" }, isAuthenticated: true }), +})); +vi.mock("@/hooks/use-mounted", () => ({ useMounted: () => true })); +vi.mock("@/hooks/use-ai-capability", () => ({ + useAiProviderState: () => ({ + configured: false, + managedBy: null, + canConfigure: true, + }), +})); + +import { I18nProvider } from "@/lib/i18n/context"; +import { AiSetupHint } from "../ai-setup-hint"; + +function dismissButton(): string { + vi.stubGlobal("window", { + localStorage: { getItem: () => null, setItem: () => undefined }, + }); + const html = renderToStaticMarkup( + + + , + ); + vi.unstubAllGlobals(); + const match = html.match( + /]*data-slot="ai-setup-hint-dismiss"[^>]*>/, + ); + expect(match).not.toBeNull(); + return match![0]; +} + +describe("the setup hint's dismiss button", () => { + it("is at least 44 px on a phone", () => { + const button = dismissButton(); + const cls = button.match(/class="([^"]*)"/)![1]!.split(/\s+/); + expect(cls).toContain("size-11"); + }); +}); diff --git a/src/components/insights/ai-setup-hint.tsx b/src/components/insights/ai-setup-hint.tsx index 6e6ea316c..cf4f3e008 100644 --- a/src/components/insights/ai-setup-hint.tsx +++ b/src/components/insights/ai-setup-hint.tsx @@ -115,7 +115,9 @@ export function AiSetupHint({ aria-label={t("insights.aiSetupHint.dismiss")} title={t("insights.aiSetupHint.dismiss")} data-slot="ai-setup-hint-dismiss" - className="-my-2 shrink-0" + // 44 px on a phone like every other mobile action; the negative + // margin keeps the header row as tall as the title needs. + className="-my-2.5 size-11 shrink-0 sm:-my-2 sm:size-10" >