fix(list): align the unread dot with the first line, not the row midpoint - #715
fix(list): align the unread dot with the first line, not the row midpoint#715lucletoffe wants to merge 1 commit into
Conversation
…oint The dot is absolutely positioned with `top-1/2`, so it centres on the whole row. In the default multi-line layout (sender / subject / preview) that puts it a full line below the checkbox and the avatar it reads as a column with — visibly out of line, and worse the taller the row. Anchor it on the first line instead: top padding + half an avatar, per density. Same fix for the messages of an expanded thread. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FTRyrFCR2N9qkpKK37GgWb
There was a problem hiding this comment.
Pull request overview
This PR adjusts the unread indicator (“dot”) positioning in the email/thread list UI so it aligns with the first line of content (checkbox/avatar row) rather than the vertical midpoint of multi-line rows, preventing visible drift as rows grow in height.
Changes:
- Repositions the unread dot in list rows by anchoring it to
var(--density-item-py)plus half of the first-line avatar/line-height. - Extracts the duplicated unread-dot markup in
thread-list-item.tsxinto a smallUnreadDothelper component. - Applies the same “anchor to first line” approach to unread dots for messages in expanded threads (
thread-email-item.tsx).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| components/email/thread-list-item.tsx | Introduces UnreadDot and replaces midpoint-centered unread-dot positioning in single/thread rows. |
| components/email/thread-email-item.tsx | Updates unread-dot positioning in expanded thread email rows to anchor on the first line. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| function UnreadDot({ density, compactAvatar }: { density: string; compactAvatar: boolean }) { | ||
| const halfFirstLine = density === 'extra-compact' ? '0.625rem' : compactAvatar ? '1rem' : '1.25rem'; |
|
While the unread dot is getting reworked, I'd appreciate if you could make it appear to screen readers, e.g., by using If you'd prefer that, I could create an issue for this and attempt submitting a PR for the newly introduced component once this PR is merged. |
The problem
The unread dot is positioned with
top-1/2 -translate-y-1/2, so it centres on the wholerow. At the default density a row is three lines tall (sender / subject / preview) while the
checkbox and the avatar sit at the top — the dot therefore lands roughly a line below them,
level with the subject or the preview. It reads as a column with those two, so the drift is
what the eye catches first, and it gets worse as rows grow (larger font, wrapped subject,
tag lozenges).
main)Screenshots taken with
DEMO_MODE=true npm run dev, dark theme, default density.The fix
Anchor the dot on the row's first line instead of its midpoint:
var(--density-item-py)plus half an avatar, following the density (
extra-compacthas no avatar, so it uses thesender line height). Extracted into a small
UnreadDotcomponent since the markup wasduplicated for the single-email and thread rows.
thread-list-item.tsx— both occurrences.thread-email-item.tsx— sametop-1/2on the messages of an expanded thread, same fix(its avatar is
sm).No layout change: the dot stays absolutely positioned, so it still costs no width.
Checks
npm run typecheckclean ·npm run lintclean (8 pre-existing warnings onmain, nonein the touched files) ·
npx vitest run→ 146 files, 2331 tests passed.Note for the mobile app
bulwarkmail/nativegrew the same indicator in #27 with the sametop: '50%', and the samedrift — bulwarkmail/native#36 fixes it there.