From 3962900035cbcb1ba79160536503fa1f9fa50b07 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Thu, 29 Oct 2026 16:23:25 +0100 Subject: [PATCH] fix: show a tag's letter in its dot and its full name with colour names on --- components/email/__tests__/tag-badge.test.tsx | 16 +++++++++++++- components/email/tag-badge.tsx | 22 ++++++++++++++++--- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/components/email/__tests__/tag-badge.test.tsx b/components/email/__tests__/tag-badge.test.tsx index 990e84bff..26f50d363 100644 --- a/components/email/__tests__/tag-badge.test.tsx +++ b/components/email/__tests__/tag-badge.test.tsx @@ -10,7 +10,7 @@ const TAGS: KeywordDefinition[] = [ describe('TagBadge', () => { beforeEach(() => { - useSettingsStore.setState({ emailKeywords: TAGS, nestedTags: true }); + useSettingsStore.setState({ emailKeywords: TAGS, nestedTags: true, showColorNames: false }); }); it('names the tag by its full path', () => { @@ -38,4 +38,18 @@ describe('TagBadge', () => { expect(screen.queryByRole('button')).not.toBeInTheDocument(); expect(screen.getByText('Work')).toHaveClass('sr-only'); }); + + // CV-01: a dot was colour only for sighted users. + it('puts the first letter in the dot', () => { + const { container } = render(); + const dot = container.querySelector('[data-tag-dot]')!; + expect(dot.querySelector('[aria-hidden="true"]')).toHaveTextContent('W'); + }); + + it('names the tag in full where a dot would go with colour names on', () => { + useSettingsStore.setState({ showColorNames: true }); + const { container } = render(); + expect(container.querySelector('[data-tag-dot]')).toBeNull(); + expect(screen.getByText('Work/Clients')).not.toHaveClass('sr-only'); + }); }); diff --git a/components/email/tag-badge.tsx b/components/email/tag-badge.tsx index f6a283496..58aaa8886 100644 --- a/components/email/tag-badge.tsx +++ b/components/email/tag-badge.tsx @@ -6,10 +6,12 @@ import { cn } from "@/lib/utils"; import { useKeywordFormat } from "@/hooks/use-keyword-format"; import type { TagScope } from "@/hooks/use-account-tags"; import { useShortenedText } from "@/hooks/use-shortened-text"; +import { useSettingsStore } from "@/stores/settings-store"; /** * How much room the surface has for a tag. - * - `badge` names the tag; `dot` only identifies it by colour. + * - `badge` names the tag; `dot` shows its colour and first letter (and the + * whole name with "Show colour names" on). */ export type TagBadgeVariant = "badge" | "dot"; @@ -61,13 +63,27 @@ export function TagBadge({ const [labelRef, shortenedName] = useShortenedText(tagNameCandidates(tagId)); const color = tagColor(tagId); const name = tagName(tagId); + const showColorNames = useSettingsStore((st) => st.showColorNames); - if (variant === "dot") { + // "Show colour names" (Settings > Accessibility): the named form even where + // only a dot fits, so no tag is told apart by its colour alone. + if (variant === "dot" && !showColorNames) { + // Not colour alone either way: the dot carries the tag's first letter, + // in the lozenge's own colours (WCAG 1.4.1). + const initial = [...name.trim()][0]?.toLocaleUpperCase() ?? ""; return ( + {name} );