From 3c5b45a506d802abc1eab97843572a4fa50dbc70 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Fri, 30 Oct 2026 00:17:19 +0100 Subject: [PATCH] fix: make unread mail stand out in the flat fields theme --- .../theme-flat-fields-unread.test.ts | 47 +++++++++++++++++++ lib/theme-flat-fields.ts | 12 ++++- 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 lib/__tests__/theme-flat-fields-unread.test.ts diff --git a/lib/__tests__/theme-flat-fields-unread.test.ts b/lib/__tests__/theme-flat-fields-unread.test.ts new file mode 100644 index 000000000..028734a19 --- /dev/null +++ b/lib/__tests__/theme-flat-fields-unread.test.ts @@ -0,0 +1,47 @@ +import { afterEach, describe, expect, it } from 'vitest'; +import { flatFieldsSkin } from '../theme-flat-fields'; + +// Under Flat fields an unread sender (600) and a read one (500) looked the +// same in Hanken Grotesk, so nobody could tell which mail was unread. The +// skin pushes unread to 700 and read senders to 400. + +function mountRow(unread: boolean, nameClass: string) { + document.body.setAttribute('data-theme-skin', 'builtin-flat-fields'); + const style = document.createElement('style'); + // The app's own weights, which the skin has to beat. + style.textContent = ` + .font-medium { font-weight: 500; } + .font-semibold { font-weight: 600; } + .font-bold { font-weight: 700; } + ` + flatFieldsSkin; + document.head.appendChild(style); + document.body.innerHTML = ` +
+
+ Ada +
+
`; + return getComputedStyle(document.getElementById('name')!).fontWeight; +} + +afterEach(() => { + document.head.innerHTML = ''; + document.body.innerHTML = ''; + document.body.removeAttribute('data-theme-skin'); +}); + +describe('Flat fields unread weight', () => { + it('sets unread senders and subjects in 700', () => { + expect(mountRow(true, 'truncate text-sm font-semibold text-foreground')).toBe('700'); + expect(mountRow(true, 'truncate text-sm font-bold text-foreground')).toBe('700'); + }); + + it('sets read senders in 400', () => { + expect(mountRow(false, 'w-32 shrink-0 truncate text-sm font-medium text-foreground/80')).toBe('400'); + expect(mountRow(false, 'truncate text-sm font-medium text-muted-foreground')).toBe('400'); + }); + + it('leaves other medium text in read rows alone', () => { + expect(mountRow(false, 'inline-flex text-xs font-medium text-sky-700')).toBe('500'); + }); +}); diff --git a/lib/theme-flat-fields.ts b/lib/theme-flat-fields.ts index 0a661d6ec..2d6ffe554 100644 --- a/lib/theme-flat-fields.ts +++ b/lib/theme-flat-fields.ts @@ -321,11 +321,21 @@ body[data-theme-skin="builtin-flat-fields"] :is(input[type="checkbox"], input[ty accent-color: var(--color-primary); } -/* Unread is a small square and a 600 weight, not a tinted row. */ +/* Unread is a small square and a heavy weight, not a tinted row. Hanken + Grotesk's 600 sits too close to the 500 of read senders to tell apart, so + unread sender and subject go to 700 and read senders drop to 400. */ body[data-theme-skin="builtin-flat-fields"] [data-tour="email-list"] .bg-accent\\/30:not(:hover) { background-color: var(--color-background); } +body[data-theme-skin="builtin-flat-fields"] [data-tour="email-list"] [data-unread="true"] .text-foreground:is(.font-semibold, .font-bold) { + font-weight: 700; +} + +body[data-theme-skin="builtin-flat-fields"] [data-tour="email-list"] [data-unread="false"] .font-medium:is([class~="text-foreground/80"], .text-muted-foreground) { + font-weight: 400; +} + body[data-theme-skin="builtin-flat-fields"] [data-tour="email-list"] svg.fill-unread { color: transparent; fill: transparent;