Skip to content

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

Open
tomeredlich wants to merge 104 commits into
dev-take-picfrom
snapshot-share-images
Open

feat(snapshot): square share images for every daily.dev surface#6544
tomeredlich wants to merge 104 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>
The page showed where the Snapshot button sits without saying whether
Snapshot is the right thing to press there. It usually is not: on a post,
a profile or a squad the destination carries more than the image can, and
the button is a secondary affordance.

Each placement now states its leading action, and the header carries the
rule the Sharing map derives, so nobody reads the page as "Snapshot
everywhere". Purple marks the surfaces where the payload is the value.

Also notes the seven built placements against the tracker's roughly
thirty, so the page is not mistaken for the full inventory.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A chip saying "leads with Link" left the reader to imagine the result.
Each surface now renders all three actions as they should ship: the
leading one labelled, the other two icon-only beside it.

Notes carry the reason rather than the mechanics. Posts and profiles
already have real per-item OG images, so an unfurled link beats a
picture of the article; streaks, achievements, takes and widgets have no
URL anyone else can open, so an image is the only thing that can carry
them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Rendering all three controls implied every surface ships all three, when
the point of the map is that one of them wins. Each placement now shows
just the recommended action, and the chip states which it is.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Showing three controls on every surface asked the reader to choose when
the Sharing map had already decided. The surface's leading action now
sits outside and the chevron opens the rest — the social targets, and
Snapshot where it is not already leading.

Built on the primitives that are on main (SocialShareList,
useShareOrCopyLink) rather than ShareActions from #6343, which was
closed and never landed. The lead prop is the seam: if that foundation
returns, this composes over it instead of duplicating it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tomeredlich and others added 2 commits August 30, 2026 16:23
The page showed seven placements against a map of twenty, so the ones
still under discussion had nowhere to be looked at. Adds the missing
thirteen as mock-ups — quote bar, end of conversation, post-upvote,
briefing, tags and sources, leaderboard page, streak popup, DevCard,
reading history, copy my feed, squad directory, best-of, invite — each
carrying the action the map gives it and the reason why.

Two shapes cover them rather than thirteen bespoke mocks: a section
header with a control on the right, and a card with one in its footer.

The header now separates what is built from what is drawn, so nobody
reads a mock-up as shipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Placement 8 was a generic card, which said nothing about where the
control actually goes. It is now the floating bar from #6352 over a live
selection: copy link, copy text, quote, share, with Snapshot alongside
them.

Rebuilt rather than imported — #6352 is closed and SelectionShareBar
never reached main — so the chrome and control set match the PR while
the component itself stays out of this branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The control section showed four Snapshot variants, two of which nothing
uses, and none of the link, share or selection-bar controls that carry
most of the placements. It now lists the six real ones, each naming the
surfaces it appears on so the set can be audited against the map rather
than trusted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A download is silent on most browsers, so pressing Snapshot looked like
it had done nothing. Success and failure now carry their semantic
variant, so the check and the alert read at a glance.

The placements page mounts the toast host and offers the three states,
because Storybook aliases the toast hook to a mock that logs to the
console — every toast in every story has been invisible. The page reaches
the real hook through the hooks barrel, which the alias does not cover.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every target we share to takes a paste — Slack, WhatsApp, X, a composer.
A file in Downloads makes the sharer go find it first, so the clipboard
leads and the download stays as the fallback where ClipboardItem is
missing or refused.

The capture is handed over as a promise rather than awaited: Safari only
honours a clipboard write inside the task that handled the gesture, and
awaiting the rasterization first loses it.

Confirms with "Image copied", in the toast style the rest of the product
already uses.

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