diff --git a/src/components/medications/__tests__/injection-site-picker.test.tsx b/src/components/medications/__tests__/injection-site-picker.test.tsx index edc2ee342..72e384667 100644 --- a/src/components/medications/__tests__/injection-site-picker.test.tsx +++ b/src/components/medications/__tests__/injection-site-picker.test.tsx @@ -247,13 +247,14 @@ describe("", () => { }); it("uses the SVG body outline as the picker surface", () => { - // Sanity check the body outline renders — head circle + torso - // path are the load-bearing visual anchors for the click targets. + // Sanity check the body outline renders — the silhouette path is the + // load-bearing visual anchor for the click targets, drawn on the + // 100x200 viewBox the iOS reference coords are calibrated against. const html = render( {}} />, ); - expect(html).toMatch(/]*viewBox="0 0 120 300"/); + expect(html).toMatch(/]*viewBox="0 0 100 200"/); expect(html).toContain('aria-label="Body outline"'); // The outer group has the localised "Once weekly on …" picker // label so the wrapper announces its role properly. diff --git a/src/components/medications/injection-site-picker.tsx b/src/components/medications/injection-site-picker.tsx index ad1210511..514f5f3f8 100644 --- a/src/components/medications/injection-site-picker.tsx +++ b/src/components/medications/injection-site-picker.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useId, useState } from "react"; import { useTranslations } from "@/lib/i18n/context"; import { @@ -12,27 +12,38 @@ import { } from "@/lib/medications/injection-sites"; /** - * v1.4.25 W4d — injection-site picker. + * Injection-site picker — anatomical front-of-body silhouette with 8 + * tappable sites. * - * Stylized front-of-body SVG with 8 click-targets. The active site - * highlights, the recommended next-site is ringed with a dashed outline - * so the user can rotate sensibly without consulting a separate guide. + * The silhouette is an INLINE SVG so it inherits the app's theme tokens + * (`currentColor` + CSS variables) and tints correctly in light/dark and + * across the zinc/Dracula palettes with no raster asset and no luminance + * key. The body is traced to the proportions the iOS client calibrated + * against (see `.planning/ios-coord/v0.12-…-injection-bodymap-coords.md`) + * so dots land on the same anatomy on both platforms. * - * Per Marc's "nichts brickt" directive the picker is opt-in — it's only + * `viewBox="0 0 100 200"` (aspect ≈0.5). `SITE_COORDS` is expressed on + * the same viewBox; the recommended-next ring, the last-used marker and + * the selected fill all read directly from those coordinates. + * + * Per the long-standing "nichts brickt" directive the picker is opt-in — * mounted from the GLP-1 dashboard tile and the optional log dialog. - * Existing medication intake flows continue to work without it (the - * intake-event row's `injectionSite` field stays NULL). + * Existing intake flows keep working without it (the row's + * `injectionSite` stays NULL). * - * Mobile-first: the picker is centred in a 320px column and remains - * touch-friendly at Pixel-5 width. SVG buttons have 44px hit areas - * (the visible circle is smaller but the