Skip to content

fix(notifications): lead post rows with the headline, and let the time follow the grey text - #6548

Open
tsahimatsliah wants to merge 2 commits into
mainfrom
feat/notification-row-readability
Open

fix(notifications): lead post rows with the headline, and let the time follow the grey text#6548
tsahimatsliah wants to merge 2 commits into
mainfrom
feat/notification-row-readability

Conversation

@tsahimatsliah

@tsahimatsliah tsahimatsliah commented Aug 27, 2026

Copy link
Copy Markdown
Member

The feedback

The new notification design makes it hard for me to focus and view article headlines; I preferred the previous layout, where simply reading the headline was sufficient.

The complaint is precise and the code confirms it.

Diagnosis

An inbox carries two genres of row:

Genre Example Payload
Social "Nimrod commented on your post" the person
Content arrival "New post in The New Stack" the article headline

The redesign applied the social template to both. On a content-arrival row that inverts the hierarchy: "New post in <b>The New Stack</b>" gets typo-callout / text-text-primary, while the headline — the only thing that decides a click — drops to typo-subhead / text-text-tertiary. On a subscribed feed most rows are content arrivals, so four consecutive rows open with the identical bold phrase and the eye has to skip past the repeated part to reach the varying part.

This is 100% rolled out (pages/notifications.tsx renders NotificationsFeed unconditionally; NotificationItemLegacy is orphaned), so there is no flag to roll back — it needs a targeted change to the row.

The change

Content-arrival rows (SourcePostAdded / SquadPostAdded / UserPostAdded) lead with the post title in primary weight. The announcing sentence becomes a quiet attribution built from the avatars rather than the server copy — The New Stack, or Luffy in AI for a squad post. The words "New post in" are dropped: you are already in the notifications inbox and the row carries a cover, so they carry no information.

Social rows are untouched. Same actor-first layout, same wording.

The timestamp moves off the title and follows the row's last grey lineThe New Stack · 3h, Scaling our cache layer · 5h — so it reads as part of the metadata trail instead of competing with the headline. A row with no grey text at all (a bare follow) gets it on a line of its own.

Before / after on a source-post row:

before                                after
New post in The New Stack · 3h        Anthropic's Claude now has a browser of its own
Anthropic's Claude now has a ...      The New Stack · 3h

Two things worth a reviewer's attention

The time is never inside a line-clamp. Every time-anchored grey line is a single-line truncating flex row with the time as a shrink-0 sibling. This is not stylistic: inline-inside-the-clamp is how the current layout can hide the timestamp entirely — a headline long enough to fill two lines clamps it away, which is reproducible at mobile width today. There is a test pinning this.

The cost: a comment snippet that is the row's last grey line truncates to one line instead of two. Rows where the comment is followed by a post title keep both lines. Called out because it is a real trade, not an oversight.

Two CSS traps in this codebase, both found by rendering rather than reading:

  • A global * { flex-shrink: 0 } means truncating text must opt back in with shrink, or it keeps its max-content width and overflows the row instead of ellipsing.
  • multi-truncate is display: -webkit-box, which blockifies when it becomes a flex item — losing both the clamp and the width. It cannot be used for the anchored lines at all, which is why those take a different branch.

Verification

  • packages/shared notifications suites: 48 passed (4 suites)
  • packages/webapp NotificationsPage: 4 passed
  • ESLint on src/components/notifications: clean, --max-warnings 0
  • tsc --noEmit: 26 errors, all pre-existing on main, none in changed files
  • Rendered in Storybook (Components/Notifications/Full page) in light + dark, desktop + 375px + 300px; no horizontal overflow (body.scrollWidth === clientWidth), and all timestamps survive at 300px

New tests cover the promoted headline, squad attribution, the actor-first fallback when there is no post to promote, timestamp anchoring, and the no-grey-text case.

Provenance

Design was chosen by simulating the alternatives in Storybook rather than by argument — six headline treatments and seven timestamp treatments, on a shared feed, with row heights and timestamp positions measured in the DOM. Two candidates were killed by measurement (one lost the timestamp at mobile width; one bought no density at all because the 48px cover sets the row height, not the text). Those exploration pages are on feat/notification-headline-emphasis and deliberately kept out of this PR.

🤖 Generated with Claude Code

Preview domain

https://feat-notification-row-readabilit.preview.app.daily.dev

@vercel

vercel Bot commented Aug 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
daily-webapp Ready Ready Preview Aug 27, 2026 2:23pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
storybook Ignored Ignored Aug 27, 2026 2:23pm

Request Review

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

…e follow the grey text

User feedback on the redesigned notifications page: article headlines are hard
to focus on, and the old layout let you decide from the headline alone.

An inbox carries two genres of row. On a SOCIAL row ("Nimrod commented on your
post") the person is the payload, and the actor-first layout is right. On a
CONTENT-ARRIVAL row ("New post in The New Stack") the article headline is the
payload and the sentence is boilerplate that repeats on every row - yet the
boilerplate carried primary weight and colour while the headline sat at
typo-subhead / text-tertiary, the quietest text in the row. Four consecutive
rows from one source opened with the identical bold phrase.

Content-arrival rows now lead with the post title in primary weight, and the
announcing sentence becomes a quiet attribution built from the avatars rather
than the server copy: "The New Stack", or "Luffy in AI" for a squad post. The
words "New post in" are dropped - you are already in the notifications inbox and
the row has a cover, so they carry no information. Social rows keep the
actor-first layout untouched.

The timestamp moves off the title and follows the row's last grey line -
"The New Stack - 3h", "Scaling our cache layer - 5h" - so it reads as part of
the metadata trail rather than competing with the headline. A row with no grey
text at all (a bare follow) gets it on a line of its own.

Two things worth knowing for review:

- Every time-anchored grey line is a single-line truncating flex row with the
  time as a shrink-0 sibling, never inside the clamp. Inline-inside-the-clamp is
  how the old layout could hide the timestamp completely on a long title at
  mobile width. The cost is that a comment snippet which is the last grey line
  truncates to one line instead of two.
- The truncating text needs an explicit `shrink`: this codebase sets a global
  `* { flex-shrink: 0 }`, and without it the text keeps its max-content width
  and overflows the row. `multi-truncate` cannot be used in these rows at all -
  it is `display: -webkit-box`, which blockifies when it becomes a flex item and
  loses both its clamp and its width.

Adds tests for the promoted headline, the squad attribution, the actor-first
fallback when there is no post to promote, the timestamp anchoring, and that the
time is never inside a clamped element.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…dit framing

The notification stories render the real component, so they pick up the new
layout on their own - but their prose described the old one and would have
shipped stale with it.

- List item / Row anatomy (new): the two genres, the attribution rule and the
  timestamp rule, each with a live row. Also the two CSS traps, because both
  cost a debugging round during implementation and neither is visible from the
  code.
- Overview: was framed as an open "readability audit" with levers to tune. The
  audit is finished, so it now opens with the rules it produced. Its levers for
  the list row described a bold title and a meta line carrying the time -
  neither is true any more.
- Full page / Use cases: point at the anatomy story rather than describing the
  layout twice.
- In-app popup: records a KNOWN GAP. InAppNotificationItem renders the title
  and nothing else, so a post arrival still reads "New post in <source>" there
  while the feed row leads with the headline. The avatar lockup is shared, the
  text layout is not. Documented rather than silently changed - it is a
  different surface and deserves its own decision.

Untouched stories with pre-existing prettier drift (Icons, Toast, _mock) are
deliberately left alone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants