Skip to content

feat(snapshot): square share images for every daily.dev surface - #6544

Draft
tomeredlich wants to merge 134 commits into
dev-take-picfrom
snapshot-share-images
Draft

feat(snapshot): square share images for every daily.dev surface#6544
tomeredlich wants to merge 134 commits into
dev-take-picfrom
snapshot-share-images

Conversation

@tomeredlich

@tomeredlich tomeredlich commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Stacked on #6426 — base retargets to main once that merges. The diff here is one commit.

Adds a Snapshot control that exports a surface as a branded 1080×1080 PNG, and the twenty card designs it captures. Easier to review in Storybook than in the diff: Features/SnapshotShare images (every image), Spec (dimensions and content contract), Edge cases (how each card degrades).

Changes

  • Capture builds on feat: add captureShareImage util for element-to-OG-image capture #6426's util: each card is a real React component rendered off-screen, rasterized by snapdom, composed onto one canvas. The background gradient is seeded from the subject's id, so a post or profile always produces the same image.
  • Twenty cards across the sharing-initiative surfaces — post, highlighted text, Happening Now, leaderboard rank, watercooler, hot take, profile, reading overview, badges, achievements, the collectible achievement slab, invite, streak, tag/source/squad, discussion, briefing, best-of, level up. Tag/source/squad share one component, as do briefing/best-of: each pair is the same object with a different label.
  • The button plays a shutter and sweeps a highlight across its face on press. Beside the bookmark on watercooler cards, on hover in leaderboard rows and achievement cards, inline elsewhere.
  • Content rules — quotes cap at 280 characters and truncate at the last word rather than being refused; headlines balance line lengths; long URLs and type names wrap inside the card; missing copy collapses instead of leaving an empty band; cards cannot outgrow the square, so a capture never clips the logo.

Not in this PR

Design review only. No data wiring — every card reads Storybook fixtures. No feature flag. No share flow: the button downloads a PNG, and onCapture is the seam for whatever replaces that. RTL is not handled yet.

Events

None.

Experiment

None.

Testing

  • shared: 365 suites / 2,579 tests. webapp: 74 / 587.
  • typecheck-strict-changed clean; eslint clean on every touched file.
  • pnpm --filter storybook build verified, and the static bundle re-checked in a browser — cards render and capture from the production build.
  • Two overflow bugs found and fixed by the edge-case page: cards could grow past the square and clip the logo, and the streak card overflowed its own card at typical values.

🤖 Generated with Claude Code

Preview domain

https://snapshot-share-images.preview.app.daily.dev

rebelchris and others added 30 commits August 6, 2026 14:00
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ass card (#6462)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…rfaced (#6463)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…#6461)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…eed cards

No two of the four directory headers were laid out the way I had drawn
them: the tag page is a centred hero with no logo, the source page is
left-aligned with its actions on a line below the title, the squad card
is a w-80 EntityCard whose menu is hover-revealed, and the best-of
archive is a month grid with no controls and no post list at all.

Hot takes are an emoji tile, title, subtitle and an upvote counter — no
menu, so it is the only list with no share route even buried. Reading
history rows lead with 'Share post via...' and drop their vote buttons
below laptop.

Feed cards removed: they are covered on the post page.

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

- ProfileHeader is an h-36 cover with a 7.5rem rounded-16 avatar pinned
  over its bottom-left and a right-aligned action row above the name, not
  beside it. Snapshot already ships in that row; Follow/Award/... render
  only for a visitor, below the handle. The widgets all carry a snapshot
  already, and their real contents are summary cards, a tag-progress grid
  and the heatmap.
- /settings/invite is three sections with a labelled TextField, a Primary
  Copy link action button and the seven-target social row. The reward copy
  belongs to #6366's unbuilt onboarding step, not this page.
- The leaderboard row is score, rank badge, avatar, name and handle, with
  the snapshot fading in at XSmall Float.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
I had only drawn the profile list row. The surface people actually meet a
hot take on is HotAndColdModal: an emoji tile, centred Title3, the quote
in Body-tertiary, an upvote pill and a bordered author footer, with the
three reaction buttons and 'Add your own hot take' beneath.

The snapshot already ships there, on the top card only and at Float,
beside the upvote pill — so the profile-list placement is a placement of
an existing card, not a new feature.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Each section is now Today plus the chosen option, with the alternatives
removed:

- Swipe modal: snapshot promoted from Float to labeled and filled.
- Profile list: snapshot beside the upvote at XSmall.
- Reading history: an icon-only copy link before the menu, always
  visible rather than hover-gated.

Dead 'lead' branches dropped from the list and history rows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both snapshot variants removed, along with the now-unreachable snapshot
target inside InviteScreen. The section keeps its Today state as a
reference point and states the conclusion outright: no change proposed,
because an image of a referral cannot be clicked and the page already
carries the most complete share UI in the product.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The settings page is complete and unreachable: a labelled TextField, a
Primary Copy link and the seven-target row, buried three levels into
settings, long after the moment a new account is most willing to bring
someone with them. So the invite is not a payload problem, it is a
placement one — which makes it a surface of its own rather than a
suggestion attached to the feed export.

The new page draws #6366's step on the real funnel chrome:
FunnelStepCtaWrapper's glass branch, the 32rem rail, StepHeadline, three
invite slots, the glass bar CTA and step dots. Snapshot is deliberately
absent throughout — a referral image cannot be clicked.

Invite & feed export becomes Copy my feed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Scoped to custom feeds and drawn where it belongs: FeedSettingsGeneralSection
already gates feed name, the emoji picker, the default-feed toggle and
delete behind isCustomFeed, so an export is a property of a feed you
built rather than a control on the feed header. The 'Share this feed'
block sits between the default toggle and Happening Now placement.

Replaces the invented feed-header mock with the real modal: seven tabs,
Cancel and a disabled Save, and every General block in its shipped order.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tomeredlich and others added 4 commits September 2, 2026 09:28
Pick emoji and the snapshot control were filling the panel width because
the block is a flex column. Both now size themselves, matching Make
default and Delete feed at w-40. 'Choose an icon' also has no description
in production, so the empty line is gone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reframed on the product call: a custom feed is something you built, so
the thing worth sending is the feed, not a picture of its posts. Copy
link leads, the top-20 text list becomes the fallback, and snapshot is
out entirely — which revises #6362's sharing-map row.

Adds the recipient side, which is what makes the share worth anything:
open the link, see whose feed it is and what adding it will do, get a new
feed named after the sharer. FeedSettingsCreate's
/feeds/new?entityId=&entityType= flow is the precedent — same thing with
a set instead of a single tag. Also drawn: the added state, and the feed
limit, which FeedSettingsCreate already treats as a real error.

Four blockers named, three of them not frontend.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Copy on add, not a live subscription.
- Sign-in required: a feed lives in an account, so a session-less visitor
  gets a sign-in state and opens the link again afterwards. No logged-out
  preview, which is also why the sample posts are dimmed and not links.
- 'Just show me the posts' removed, and the feed-limit copy now names the
  only two ways out — delete a feed or upgrade.
- The remaining open question restated plainly: whether an added feed
  consumes a feed slot.

The story was titled 'Copy my feed' while its heading read 'Share my
feed', which made the two halves look like separate pages; renamed so
the sharer and recipient sections are visibly one page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add stays live and the failure comes back as a real toast — NotifContainer
with the Error variant's AlertIcon — naming both ways out. Nothing is
disabled up front, because we cannot know the recipient is at their cap
until they press, and a dead button explains nothing.

That also settles the last open question: an added feed uses a slot like
any other, so there is one kind of feed, one limit and one message.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tomeredlich and others added 2 commits September 2, 2026 11:12
Three more celebrations already ship with no share route, drawn before
and after: TopReaderBadgeModal, which already generates an image for its
Download button and shares none of it; the ten-tier streak milestone
system in streakTiers.ts, which is far richer than the day count we had
been drawing; and ReputationPrivilegesModal.

Six more listed rather than drawn, because each needs a call on whether
the moment is worth interrupting: the achievement unlock modal, levelling
up, curating the profile showcase, being awarded, a post that did well
via analytics or a boost, and going Plus.

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

Being awarded and a post that did well move from the listed set into
drawn before/after frames, joining the top reader badge and the streak
tiers. Reputation privileges and going Plus removed.

The awards moment is drawn from the recipient's side — ListAwardsModal's
cores total and giver list — and analytics gets two placements, an icon
in the header and a labeled control under the stats where the numbers
have just made the case.

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.

7 participants