From 1842e23c8142cc81d0b0f148e545cead4e187f60 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 29 Apr 2026 08:51:25 +0200 Subject: [PATCH] refactor(person-mention): centralise PERSON_MENTION_SELECTOR constant Markus flagged that 'a.person-mention' is a magic string repeated four times in TranscriptionReadView, plus the CSS rule, plus tests. Extract into a single exported constant so the renderer template, the delegated event handlers, and the consumer-side selectors all import the same value. Co-Authored-By: Claude Sonnet 4.6 --- .../src/lib/components/TranscriptionReadView.svelte | 12 ++++++++---- frontend/src/lib/utils/mention.ts | 10 ++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/frontend/src/lib/components/TranscriptionReadView.svelte b/frontend/src/lib/components/TranscriptionReadView.svelte index d0e8b32f..9f48f651 100644 --- a/frontend/src/lib/components/TranscriptionReadView.svelte +++ b/frontend/src/lib/components/TranscriptionReadView.svelte @@ -2,7 +2,11 @@ import type { TranscriptionBlockData } from '$lib/types'; import type { components } from '$lib/generated/api'; import { splitByMarkers } from '$lib/utils/transcriptionMarkers'; -import { renderTranscriptionBody, type SafeHtml } from '$lib/utils/mention'; +import { + renderTranscriptionBody, + type SafeHtml, + PERSON_MENTION_SELECTOR +} from '$lib/utils/mention'; import PersonHoverCard from './PersonHoverCard.svelte'; import type { HoverData, LoadState } from '$lib/types/personHoverCard'; import { goto } from '$app/navigation'; @@ -163,15 +167,15 @@ async function handleMentionClick(event: MouseEvent) { function attachMentionHandlers(node: HTMLElement) { function onEnter(e: Event) { const t = e.target as HTMLElement; - if (t.matches?.('a.person-mention')) handleMentionEnter(e); + if (t.matches?.(PERSON_MENTION_SELECTOR)) handleMentionEnter(e); } function onLeave(e: Event) { const t = e.target as HTMLElement; - if (t.matches?.('a.person-mention')) handleMentionLeave(e); + if (t.matches?.(PERSON_MENTION_SELECTOR)) handleMentionLeave(e); } function onClick(e: MouseEvent) { const t = e.target as HTMLElement; - if (t.matches?.('a.person-mention')) handleMentionClick(e); + if (t.matches?.(PERSON_MENTION_SELECTOR)) handleMentionClick(e); } // mouseenter does not bubble — capture it. node.addEventListener('mouseenter', onEnter, true); diff --git a/frontend/src/lib/utils/mention.ts b/frontend/src/lib/utils/mention.ts index 16203459..27451c4d 100644 --- a/frontend/src/lib/utils/mention.ts +++ b/frontend/src/lib/utils/mention.ts @@ -1,5 +1,15 @@ import type { MentionDTO, PersonMention } from '$lib/types'; +/** + * Single-source CSS selector for rendered person-mention anchors. Used by: + * - layout.css (.person-mention rule, focus ring, underline) + * - TranscriptionReadView (delegated mouseenter/leave/click handlers) + * - unit + e2e tests + * + * Keep these in sync — the renderer template below emits exactly this class. + */ +export const PERSON_MENTION_SELECTOR = 'a.person-mention'; + /** * Branded string type for HTML that has been pre-escaped and assembled by * one of the trusted renderers in this module. The brand exists so that