Skip to content

feat(feed): add the feed hero section behind a flag - #6515

Open
tsahimatsliah wants to merge 3 commits into
mainfrom
claude/hero-carousel-layout-e5e06u
Open

feat(feed): add the feed hero section behind a flag#6515
tsahimatsliah wants to merge 3 commits into
mainfrom
claude/hero-carousel-layout-e5e06u

Conversation

@tsahimatsliah

@tsahimatsliah tsahimatsliah commented Aug 24, 2026

Copy link
Copy Markdown
Member

What

A hero section above My Feed and Popular: a carousel of the current headlines, the Happening Now list beside it, and an ad in a column of its own.

Behind feed_hero, default off.

Layout

The section lays out on the feed grid's own column count rather than on viewport thresholds of its own, so it reflows exactly when the feed does and its column edges land on the grid's rather than beside them.

Columns Featured Rail Ad
1 (or any list feed) lead story as a list card headlines below it feed keeps it
2 1 (standard card) 1 feed keeps it
3 2 (wide card) 1 feed keeps it
4–5 the remainder 1 1
6 the remainder 2 1

A feed rendering as a list takes the stacked shape whatever its column count says, so the section reads as the same kind of thing as the rows under it.

The featured card

The existing featured-wide cards gain a hero prop. The cover fills its column instead of being letterboxed, and the card sizes its split from container queries on its own width — the hero is only ever as wide as the reader's feed grid, so a wide monitor set to three cards gives it half the room a five-card feed does. Under 40rem the cover moves under the copy; from 52rem the copy keeps two of five for the 40/60 split.

The card height is fixed, so the summary is clamped to the whole lines actually left under the headline (useFittedLineClamp). The action row keeps its place under a headline of any length, and the copy stops on a line rather than being sliced through the middle.

Making room in the feed

Three new Feed settings, all off unless the hero is on:

  • disableHighlightCards — the hero already shows those headlines, so the grid does not repeat them.
  • skipFirstAd — the hero seats a placement, so the grid stands its first one down and the reader does not meet two before the first post. The slot is shifted, not dropped: the creative moves to the next slot instead of being fetched and discarded.
  • deferWideCards — the hero already leads with a full-size card, so the grid's first row stays single-column.

skipFirstAd follows the hero's actual placement, which only exists once its column exists and an ad has come back for it — so the feed gets its own placement back whenever the hero has none.

Also

PostTypeToTagCard / PostTypeToTagList move out of FeedItemComponent into cards/common/gridCards.ts and listCards.ts, so the hero uses the same mapping rather than a second copy of it.

Headline clicks in the hero report the same feedHighlightsLogEvent the in-feed highlights card does, so the events do not disappear when the flag is on.

Testing

  • feedHeroShape.spec.ts — every column count fills its row exactly; list feeds stack.
  • FeedHeroCarousel.spec.tsx — stacked leads with one story and pages nothing; split and wide page through all of them.
  • Feed.spec.tsx — highlights dropped, and the first ad slot dropped while the survivor keeps its index.
  • feedHighlightColSpan.spec.ts — the wide-card row floor is measured in rows, not items.
  • Storybook: Features/Feed/Hero.

Preview domain

https://claude-hero-carousel-layout-e5e0.preview.app.daily.dev

🤖 Generated with Claude Code

@vercel

vercel Bot commented Aug 24, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated
daily-webapp Ready Ready Preview Sep 8, 2026 8:38pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
storybook Ignored Ignored Sep 8, 2026 8:38pm UTC

Request Review

Copy link
Copy Markdown
Member Author

test_shared is red on 837fc2c, and it is not this PR's.

The failure is src/hooks/usePlusSale.spec.tsx:

● usePlusSale › is active with a configured campaign and exposes its copy
  expect(result.current.isActive).toBe(true)
  Expected: true
  Received: false

The runningSale fixture hardcodes endDate: '2026-09-01T00:00:00.000Z'. That date passed on 1 September, so usePlusSale now correctly reports the campaign as inactive and the assertion fails. A time bomb that went off — nothing in the hook or the fixture changed, the calendar did. It fails the same way on main, so it is currently red on every open PR.

Running the full shared suite locally on this branch's exact tree: 2598 passed, 1 failed — that one. usePlusSale is not in this PR's diff.

Re-running the job would fail identically, since the failure is deterministic on the current date rather than flaky, so I have not spent a re-run on it.

The fix is one line, and I verified it locally (all 8 tests in the file pass, including the expiry case, which sets its own relative date and is unaffected):

-  endDate: '2026-09-01T00:00:00.000Z',
+  // Relative so the fixture can't expire on the calendar: a running campaign is
+  // one whose end date is still ahead. The expiry case below sets its own.
+  endDate: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),

I have deliberately not pushed it here — it is unrelated to this PR and belongs in its own change so it can land for everyone rather than waiting on this review. Happy to open that separately if useful.


Generated by Claude Code

tsahimatsliah and others added 2 commits September 8, 2026 23:07
… maps

Groundwork for the feed hero section.

The featured-wide cards gain a `hero` prop: the cover fills its column
instead of being letterboxed, the copy sizes itself from container queries
on the card's own width rather than the viewport's, and the summary is
clamped to the whole lines the fixed card height actually leaves, so the
action row keeps its place under a headline of any length.

`PostTypeToTagCard` and `PostTypeToTagList` move out of FeedItemComponent
into gridCards.ts and listCards.ts so the hero can reach the same mapping
rather than keeping a second copy of it.

The feed gains three settings a surface above it can use to make room:
`disableHighlightCards`, `skipFirstAd` and `deferWideCards`. The first ad
is shifted rather than dropped, so the creative moves to the next slot
instead of being fetched and discarded.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A hero above My Feed and Popular: a carousel of the current headlines,
the Happening Now list beside it, and an ad in a column of its own.

The section lays out on the feed grid's own column count rather than on
viewport thresholds of its own, so it reflows when the feed does and its
column edges land on the grid's. The rail earns a second column at six,
the ad earns one at four, and the featured card takes what is left. A feed
rendering as a list stacks instead: the lead story as a list card with the
headlines under it.

While the hero seats an ad the grid stands its own first placement down,
and the highlights card is dropped from the grid since the hero already
shows those headlines. Headline clicks report the same events the in-feed
highlights card does.

Flag `feed_hero`, default off.

Mockup-to-eng-pass: 1

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tsahimatsliah
tsahimatsliah force-pushed the claude/hero-carousel-layout-e5e06u branch from 4395301 to dbb1520 Compare September 8, 2026 20:10
@tsahimatsliah tsahimatsliah changed the title Add feed hero section with carousel, highlights, and ad placement feat(feed): add the feed hero section behind a flag Sep 8, 2026
Removes the hero's narration of its own history — rejected approaches,
pixel measurements from debugging, and a line-clamp note repeated once
per card — leaving why-notes for the constraints that are unguessable
from the code.

Also drops `useFeedHeroAd`'s `enabled` parameter, which had one caller
passing a literal true.

Mockup-to-eng-pass: 1

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.

1 participant