Skip to content

feat(profile): share the profile as an image or a link - #6580

Open
tomeredlich wants to merge 9 commits into
mainfrom
claude/profile-content-draft-pr-368a12
Open

feat(profile): share the profile as an image or a link#6580
tomeredlich wants to merge 9 commits into
mainfrom
claude/profile-content-draft-pr-368a12

Conversation

@tomeredlich

@tomeredlich tomeredlich commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Gives the profile surface the share controls it was missing.

Changes

  • Snapshot — a control that captures its target element as a branded 1200×630 PNG and puts it on the clipboard, falling back to a download where ClipboardItem is unavailable. Five placements: the header action row beside edit, the Reading Overview / Badges & Awards / Achievements widget headers, and each achievement card on hover or keyboard focus.
  • Copy link in the header, matched to the buttons already there at Medium Float. On a copy the icon swaps to the upvote button's filled avocado arrow and spins through copy-confirm, the same 0.4s curve as its spinAndScale, so the button confirms rather than leaving the toast to carry it. A new keyframe in the shared Tailwind config, off under prefers-reduced-motion. Sharing a profile is for getting followed, and an image cannot be followed. Reuses the existing ShareProfile event, so the header stops being an analytics blind spot beside the ⋯ menu's Share.
  • DevCard leads with Share — Download keeps its place at Float; Share leads at Primary, opening the native sheet on mobile and copying the link on desktop. It fires ShareDevcard, which already existed in log.ts with no caller. The card is already an image, so wrapping it in another one adds nothing.
  • Copy confirmation — the header's copy link swaps to the upvote button's filled avocado arrow and spins through the same curve, so the gesture that means "that worked" looks the same in both places.
  • Capture foundationcaptureShareImage rasterizes the target with snapdom, fits it inside the frame on the current theme's background and draws the daily.dev logo bar. A cross-origin image without CORS headers leaves snapdom's inliner pending forever, so the capture times out rather than spinning the button.

Notes for review

The achievement card's control sits out of flow. In flow it took 28px from the middle column and pushed long names into an ellipsis to reserve room for a button that is invisible until hover — Hello, is it me you're looking for? truncated where production does not. It is positioned from a wrapper element rather than via className, because SnapshotButton sets relative on itself and equal-specificity position utilities are resolved by stylesheet order, not class order.

AchievementCard also renders inside two w-80 hover popovers (the profile showcase and the widget), so those show the control too. Nothing is lost there; gating it is a product decision, not a constraint.

Events

No new events. Reuses ShareProfile and ShareDevcard, both already in featureManagement's sibling log.ts.

Experiment

None. No feature flag — the controls are unconditional on the profile.

Manual Testing

Verified anonymously on the deployed preview at 1440 and 375, desktop and MobileL: all placements render, the achievement control appears on hover only, captures succeed end-to-end, and achievement title widths match production exactly (229px, zero truncated). SnapshotButton.spec.tsx covers clipboard success, the download fallback, a failed capture, and the onCapture seam.

The DevCard screen is behind login, so its Share button is unverified.

On those affected packages:

  • Have you done sanity checks in the webapp?
  • Have you done sanity checks in the extension?
  • Does this not break anything in companion?

Did you test the modified components media queries?

  • MobileL (420px)
  • Tablet (656px)
  • Laptop (1020px)

Review links

Preview: https://claude-profile-content-draft-pr.preview.app.daily.dev

Preview domain

https://claude-profile-content-draft-pr.preview.app.daily.dev

@vercel

vercel Bot commented Sep 2, 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 3, 2026 2:55pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
storybook Ignored Ignored Sep 3, 2026 2:55pm UTC

Request Review

tomeredlich and others added 4 commits September 2, 2026 17:36
Adds a Snapshot control that rasterizes any element with snapdom, fits it
inside a 1200x630 frame on the current theme's background and draws the
daily.dev logo bar. The PNG goes to the clipboard, because a paste beats a
file in Downloads for every place we share to, and falls back to a download
where ClipboardItem is unavailable.

A cross-origin image without CORS headers leaves snapdom's inliner pending
forever, so the capture times out rather than spinning the button.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Five placements: the header action row beside edit, the Reading Overview,
Badges & Awards and Achievements widget headers, and each achievement card on
hover or keyboard focus.

The achievement card's control sits out of flow. In flow it took 28px from
the middle column and pushed long names into an ellipsis to reserve room for
a button that is invisible until hover. It is positioned from a wrapper
element because SnapshotButton sets `relative` on itself, which beats an
`absolute` passed through className.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The header gains a copy-link control beside snapshot, matched to the buttons
already there at Medium Float: sharing a profile is for getting followed, and
an image cannot be followed. It reuses the existing ShareProfile event, so
the header stops being a blind spot beside the ⋯ menu's Share.

The DevCard flips its default from private save to public post. Download
keeps its place at Float; Share leads at Primary, opening the native sheet on
mobile and copying the link on desktop, under the ShareDevcard event that
already existed and had no caller.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The design page behind these controls: where each one sits, on desktop and
mobile, against the alternatives that were rejected.

Mockup-to-eng-pass: 1

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tomeredlich
tomeredlich force-pushed the claude/profile-content-draft-pr-368a12 branch from 88cede3 to 3e9e531 Compare September 2, 2026 14:48
@tomeredlich tomeredlich changed the title feat(profile): snapshot the profile header, its widgets and achievements feat(profile): share the profile as an image or a link Sep 2, 2026
The header's copy link relied on the toast alone. It now swaps to the
upvote button's filled avocado arrow and spins through the same curve,
so the gesture that means "that worked" looks the same in both places.

The Storybook page drew each of the three surfaces twice, before and
after, plus a louder copy-link treatment we did not take. Only the
shipped state remains, and the props that switched between states go
with the halves they served.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The three widget headers took Button's default Small, which sat heavier than
the Learn more and 12/40 links beside them. XSmall matches the achievement
card's control and the weight of the text it shares the row with. The header
button keeps Medium, where it is matched to edit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The design page has served its purpose: the controls it compared are shipped
and reviewable on the profile itself. Removing it takes the surface chrome
with it, since nothing else imported either file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A refused clipboard write rejected out of useCopyLink, so the caller got no
toast, no copied state and an unhandled rejection: the button read as dead.
It now reports the failure, and the copied state is set only after the write
lands, so a confirmation cannot claim a copy that did not happen. The
missing-link path stops reporting a copy for the same reason.

Two strict-mode errors in the file surfaced once it entered the changed set.
An optional getLink was invoked unconditionally, and useCopyText passed a
possibly undefined value to writeText, which would have put the string
"undefined" on the clipboard.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The header's copy link already swapped to the upvote arrow, but the profile
page's other copy control — the Public profile & URL row — only filled its
copy icon, so the same gesture confirmed two different ways on one page.

Both now render CopyConfirmIcon, which carries the arrow, the avocado and the
spin in one place instead of each caller repeating the class list.

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