diff --git a/src/__tests__/inline-action-guard.test.ts b/src/__tests__/inline-action-guard.test.ts new file mode 100644 index 000000000..82b6fccba --- /dev/null +++ b/src/__tests__/inline-action-guard.test.ts @@ -0,0 +1,121 @@ +/** + * A small text action inside a line of content goes through `InlineAction` + * (`src/components/ui/inline-action.tsx`). + * + * Thirty-odd hand-rolled copies of the same "underlined small text link" + * carried three different focus rings, none at all on half of them, and a + * 16 px touch target on a phone. The primitive owns the 44 px floor on a + * coarse pointer and the ring; this guard keeps a new copy from appearing + * beside it. + * + * Matched: a `', + }, + { + path: "components/z.tsx", + source: 'Go', + }, + ]; + expect(findHandRolledInlineActions(planted)).toEqual([ + "components/x.tsx:Link", + "components/y.tsx:button", + ]); + }); + + it("is used where the copies were", () => { + const users = files.filter((f) => f.source.includes(" - {t("mood.mentalWellbeingLink")} -
{sourceLink ? ( - - - {t("targets.sourceLabel", { - source: sourceName(target.source, t), - })} - - + + + + {t("targets.sourceLabel", { + source: sourceName(target.source, t), + })} + + + ) : ( {t("targets.sourceLabel", { diff --git a/src/components/insights/sleep/chronotype-card.tsx b/src/components/insights/sleep/chronotype-card.tsx index 14c0e66be..3220acd6c 100644 --- a/src/components/insights/sleep/chronotype-card.tsx +++ b/src/components/insights/sleep/chronotype-card.tsx @@ -8,6 +8,7 @@ import { Card, CardContent, CardHeader } from "@/components/ui/card"; import { LearningGate } from "@/components/ui/learning-gate"; import { TileHeader } from "@/components/insights/tile-header"; import type { ChronotypeDto } from "./use-sleep-rhythm"; +import { InlineAction } from "@/components/ui/inline-action"; /** Minutes-of-day → "HH:MM" wall-clock label (24 h, zero-padded). */ function clockLabel(minutesOfDay: number): string { @@ -90,12 +91,12 @@ export function ChronotypeCard({ chronotype }: { chronotype: ChronotypeDto }) { )}
- + {showAdvanced && (
diff --git a/src/components/insights/trends-row.tsx b/src/components/insights/trends-row.tsx index b62e8e06b..eda495290 100644 --- a/src/components/insights/trends-row.tsx +++ b/src/components/insights/trends-row.tsx @@ -23,6 +23,7 @@ import { type TrendAnnotationStatus, } from "./trend-annotation"; import { useUnitDisplay } from "@/hooks/use-unit-display"; +import { InlineAction } from "@/components/ui/inline-action"; /** * Trends row — a small chart per metric above a one-sentence @@ -339,15 +340,20 @@ export function TrendsRow({ is used but was unreachable from Insights. The link sits below the caption so the chart keeps its own interactions. */} {config.detailHref ? ( - - {t("insights.trendsRow.viewDetail", { metric: title })} -
); diff --git a/src/components/insights/workout-detail/stats.tsx b/src/components/insights/workout-detail/stats.tsx index 36002d3bd..4aa93b56c 100644 --- a/src/components/insights/workout-detail/stats.tsx +++ b/src/components/insights/workout-detail/stats.tsx @@ -28,6 +28,7 @@ import { formatPace, formatDurationMinutes, } from "./format"; +import { InlineAction } from "@/components/ui/inline-action"; interface StatTileProps { icon: ReactNode; @@ -199,14 +200,15 @@ export function WorkoutDetailStats({ workout }: WorkoutDetailStatsProps) { )} {workout.previousWorkoutId ? ( - - {t("insights.workouts.detail.previousSessionLink")} - - + ) : null}