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 (
+ {initial}
{name}
);