feat(post): bring the focus card to parity with the classic layout for the post_redesign experiment - #6658
feat(post): bring the focus card to parity with the classic layout for the post_redesign experiment#6658tsahimatsliah wants to merge 31 commits into
Conversation
PhoneTopAdStrip renders in the layout banner, outside the page, and gated itself on useOrganicAdsenseSlots() alone. In the post_redesign arm the page never loads adsbygoogle (the focus card carries no slot markup), so for a logged-out phone visitor the strip pinned a reserved-height empty box that could neither fill nor collapse, and offset the auth banner below it. The page's redesign decision now lives in usePostPageRedesign, and the page's own getLayout renders the banner with the ISR post so the strip is skipped whenever the focus card renders. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rge) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…evert before merge) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The laptop signup banner was excluded from the redesign arm since the focus card landed, so logged-out visitors in treatment lost the page's main conversion surface. Render it for both layouts; the focus card gets bottom clearance because it ends in the thread, where the classic page ends in the footer the fixed banner already covers. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The post_redesign treatment dropped every AdSense unit for logged-out visitors, so the experiment compared inventory as much as layout. The focus card now takes the same five placements the classic layout renders (top leaderboard, TLDR MPUs, MPU after the direct-sold widget, MPU above the discussion, comment-thread MPUs) through one ads prop the page builds once for both layouts, and the pinned phone strip returns to both. The arms now differ in layout only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…eriment-impact-824ab5 # Conflicts: # packages/webapp/pages/posts/[id]/index.tsx
A squad post sharing a tweet reached the focus card as if the tweet were an article: tweet text as the H1, its media as a cover thumbnail, the AI summary as a TLDR. The classic layout renders the same post as an embedded tweet card, so the focus card now does too, keeping the sharer's commentary above it and the read CTA below. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
No read CTA and no tags under a shared tweet: the tweet card is the whole post, and the classic layout never shows tags on share posts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…cus card The classic layout only threads the organic units through PostContent, so squad and collection posts carry the pinned phone strip alone. The focus card took the whole set for every eligible type, which gave a collection four units where the control arm has one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The classic rail MPU sat in the sidebar; on the focus card it was inline under the direct-sold widget. From 92rem the unit now sits in the gutter to the right of the centred column, sticky under the header, and the column stays exactly where it is. Narrower viewports keep it inline. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…edesign The /articles template kept the classic layout regardless of the arm, so a visitor landing there and one landing on /posts saw different designs in the treatment. It now renders the same focus card behind the same flag, with the template's own rules intact: light mode, no signup surfaces, noindex, the hard-navigation guard and the read slot map. The single-column design has no widget rail, so of the three rail units only slot 11 has a home, beside the column on wide viewports; slots 12 and 19 stay with the classic template. The direct-sold widget stays off, as it is on the classic template. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The rail prop takes the classic rail's units in order: the two MPUs in flow and the 300x600 tower pinning last, exactly as they sit at the end of the classic widget column. The organic post page keeps its single sticky unit. Below the rail breakpoint only the first unit has an inline home. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
With the rail hanging off an independently centred column the pair read off-balance. The column and rail now centre together, so the column shifts left by half the rail's width only when a rail renders, and the page wrappers widen at the rail breakpoint to hold both. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…lock" This reverts commit d84f566.
… read rail on phones A shared video carries no read CTA and no tags on the classic share layout; the focus card now matches, keeping the embed and summary. The arbitrage rail units gain the classic template's hideOnPhone so the phone density budget stays at the strip, one in-content unit and the above-comments MPU. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The focus card set a sharer's commentary as bold title text with the line breaks kept, so a long post read as a wall of headline. The classic share layout renders the composer's own markdown from titleHtml; the focus card now does the same, with the plain title as the fallback. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
titleHtml collapses the author's line breaks into one paragraph, so rendering it lost the structure they typed. The raw commentary keeps the breaks; it now renders with them in body type rather than as a title. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… flag (revert before merge)" This reverts commit b53c6aa.
…efore merge)" The flag default returns to the control value; GrowthBook owns the ramp. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…eriment-impact-824ab5
With ads splitting the TLDR the snapshot icon sat on its own line under the segments; it now trails the last segment's line, as it does on the plain TLDR. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The classic squad template (share, freeform, welcome) never lists tags; only the article, video and collection templates do. The focus card followed the article template for every type. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Scoped to *.preview.app.daily.dev so tests and production are untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…eriment-impact-824ab5
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ries, keep the body unit on phones Rail units no longer carry positioning of their own: the classic rail received the focus card's sticky classes through the shared element and pinned mid-rail, and the focus card's inline fallback pinned in the column. The focus card now pins its last rail unit itself. Video summaries split into segments on the focus card as they do on the classic layout, and on /articles the first body unit keeps its phone placement when the card renders a body instead of a summary. The preview-host review override resolves after mount so the server and the first client render agree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Between the laptop breakpoint and the floating-rail threshold the column and rail now centre together as one block, the column narrowing to fit, so laptops keep every rail unit instead of the single inline fallback. The wide-screen and below-laptop placements are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
idoshamun
left a comment
There was a problem hiding this comment.
Summary
The treatment arm is brought up to the control arm's ad set slot-for-slot on /posts (verified: carriesInPageAds matches what PostContent vs SquadPostContent/CollectionPostContent actually forward on classic, and useOrganicAdSlots()'s canRender defaults to true, so the control path is untouched). The share/tweet/commentary parity work and the tests around it look right.
Three things I'd want fixed before this starts an experiment, plus a few smaller ones. Details are inline.
Blocking
useIsPreviewHostforces the treatment on every preview host and is self-declared as "revert before merge"./articlestreatment column measures 624px below 92rem, under the 745px the leaderboard needs, so slot 2 resolves to 320x100 where control gets 728x90.post_redesignis still evaluated (i.e. enrolled) for?author/?squadsessions that can only ever render the classic layout.
Non-blocking, not attached to a diff line
- Two doc blocks are now contradicted by this change and will mislead the next reader:
useReadAdSlots.tsstill says "the post page passes false in the focus-card redesign arm", and the/articlespage header still says "Lives on its own route so/posts/[id]and the focus-card redesign are untouched". Same for the PR description's "Not changed, by design: Tags render on squad posts" —showTagsnow fixes exactly that. - The focus card's discussion panel never renders
AdAsComment, which classic shows to non-Plus readers whencommentAdsis absent. Irrelevant while the audience isloggedIn: false, but it is a monetisation difference the moment logged-in users enter the experiment — worth stating as a known gap rather than discovering it in the readout.
Verification
- Root
AGENTS.md+ flag/experiment rules read - Control arm traced: flag off leaves
/postsand/articlesmarkup and slot sets unchanged - Slot parity cross-checked against
ReadPostContent,BasePostContent,SquadPostContent,slots.ts,resolveAdSizes - Not run: package tests / strict typecheck (not executed here, so not claimed)
- Not verified: rendered widths at 1366px, 1440px and 1472–1560px with the sidebar expanded and collapsed
Reviewed by AI.
- Drop the preview-host override: the flag alone decides the arm. - Gate flag evaluation on the surface being able to render the redesign, so ?author and ?squad sessions are never enrolled; one evaluation site in usePostRedesign, which the page composes with its own rule. - Key the floating rail off the space the card's own box leaves to the right of the column, measured with a ResizeObserver, instead of a viewport query that cannot see the sidebar or the wrapper. - Widen both page wrappers to 72rem so the laptop column clears 728px and the leaderboard is requested at its booked size, as on classic. - Render every rail unit inline below laptop, matching the classic rail that stacks under the article from tablet up. - Render the summary above a hosted body when the ad template asks for segments, so collections keep their TLDR units. - Render AdAsComment in the focus card discussion for non-Plus readers when no programmatic comment units are present, as classic does. - Drop the dead canRender parameter and the stale docblocks. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Thanks for the review. Everything inline is addressed in acee305 and the threads are resolved with the specifics. On the summary items without a diff line:
Still to confirm on the preview once this build is up: requested leaderboard sizes at 1366 and 1440, and the 1472 to 1560 band with the sidebar expanded and collapsed. Will post the numbers here. |
What
Pre-flight for starting the
post_redesignexperiment: the treatment arm (focus card) now carries everything the control arm carries, on/postsand on the/articlesad template, so the arms differ in layout only.Control vs treatment, measured page by page on laptop and phone: https://claude.ai/code/artifact/6f52e0e9-a0df-4856-8aa4-4c1464ecadbe
Changes
adsprop onPostFocusCard: leaderboard, in-content MPUs (TLDR and hosted body), above-comments MPU, comment MPUs, phone strip. Only article and video posts carry in-page units on/posts, as on classic; other types keep the strip alone. Before this the treatment arm had zero programmatic ads for logged-out visitors./articlesfollows the same flag and renders the focus card in the treatment arm with the template's own slot map and rules intact: light mode, no signup surfaces, noindex, hard-navigation guard,read_adskill switch, no direct-sold widget. Summary segments render above a hosted body, as on the classic template.AdAsCommentrenders in the focus card discussion for non-Plus readers when no programmatic comment units are present, as classic does.usePostRedesignonly evaluates the flag when the surface can render the redesign, so?author/?squadsessions are never enrolled. One evaluation site, shared by/posts,/articlesand the modal.Merged with main after Kueez replaced AdSense (#6664); same slot numbers, Prebid loader.
Not changed, by design (from the original focus-card PR)
Tests
PostPage.tsx: signup banner on the focus card; identical mounted ad-slot set on both layouts (article, video); collection keeps the strip alone; rail never pinned in flow; laptop rail column; snapshot icon in the last segment;?authornever evaluates the flag.ReadArticlePage.tsx: both arms of/articles; identical mounted set for an article and for a collection (summary and body units).PostFocusCard.spec.tsx: shared tweet, shared video, tags per template, commentary type.Before starting the experiment (GrowthBook)
Logged-out visitors are in the audience by default (
loggedIn: false). With this branch that is safe for revenue.Pre-existing and unrelated:
/articlesrenders dark in both arms on production although the template asks for light mode.🤖 Generated with Claude Code
Preview domain
https://claude-post-modal-experiment-imp.preview.app.daily.dev