Skip to content

feat(share): surface a copy-link control on profile headers#6354

Draft
tsahimatsliah wants to merge 3 commits into
claude/website-sharing-visibility-be6b32from
claude/share-profile
Draft

feat(share): surface a copy-link control on profile headers#6354
tsahimatsliah wants to merge 3 commits into
claude/website-sharing-visibility-be6b32from
claude/share-profile

Conversation

@tsahimatsliah

@tsahimatsliah tsahimatsliah commented Jul 22, 2026

Copy link
Copy Markdown
Member

Part of the sharing visibility initiative. Builds on PR 1 (#6343) — base branch is claude/website-sharing-visibility-be6b32, not main.

What changed

The share action on a profile lived only inside the ... options menu, and the owner's only share affordance (the Public profile & URL widget) is laptop:hidden, so a signed-in user on desktop had no way to share their own profile at all. This promotes it to a real control.

ProfileHeader.tsx — the canonical placement (all breakpoints, both profile types)

  • Own profile: copy-link button next to Edit profile.
  • Public profile: the button fills the slot the edit button used to reserve (it renders invisible there today purely to hold the row's height), so the layout height is unchanged and no dead placeholder is left behind.

profile/Header.tsx — the pinned mobile bar

  • Shows the same control, but only while pinned (sticky). Unpinned, the profile card directly below owns it; rendering both would put two identical copy buttons on one screen.
  • Share is promoted out of the ... menu here.

ProfileActions.tsx — share promoted out of its ... menu too; the new button sits directly above it on the same card.

CustomFeedOptionsMenu.tsxshareProps is now optional; omitting it drops the Share entry. Backwards compatible, no other call site changes. This is the only shared-component touch outside profile/.

New

  • profile/ProfileShareButton.tsx — thin wrapper over PR 1's ShareActions that pins the share text, ReferralCampaignKey.ShareProfile, and the analytics payload so every profile surface behaves identically. Mobile = single tap to the native share sheet; desktop = the network popover.
  • hooks/profile/useShareProfileEnabled.ts — resolves the per-topic flag and the master kill-switch in one place.

Research principle #6 — share stays distinct from Follow

Share is a Float icon control in the header's top-right utility slot; Follow is the filled primary CTA further down the card, inside ProfileActions. Different region, different weight, different variant — they never sit in the same control group. In the pinned bar, ml-1 separates the utility icon from the Follow group.

Logging

Reuses the existing LogEvent.ShareProfile (the event already emitted by the menu item and the owner share widget, so metrics stay comparable) with target_type: TargetType.ProfilePage and extra: { provider, origin: Origin.Profile }. No new Origin value was needed.

Flag

share_profile, default false, appended at the end of featureManagement.ts. Gated via useConditionalFeature and useSharingVisibility(). Flag-off is pixel-identical to the PR 1 branch — asserted in Jest (ProfileHeader.spec.tsx: the invisible edit placeholder is preserved, no share control renders anywhere).

OG image — deferred, on purpose

A per-profile unfurl card (mini dev-card with handle + stats) would make a shared profile land much harder. It is not in this PR:

  • The repo has no OG-image library. The pattern is a server-screenshotted Next.js page under packages/webapp/pages/image-generator/ (devcards/[userId].tsx, badges/[badgeId].tsx, id="screenshot_wrapper", ISR).
  • A new image-generator/profiles/[userId].tsx route is only half the work: the backend screenshot service needs a route registered for it, and getProfileSeoDefaults needs to emit the resulting og:image. That is a cross-repo dependency with its own rollout.

Shipping the affordance now and the image as a follow-up keeps this PR reviewable, per the brief's explicit guidance to defer rather than half-build.

Backend dependencies

None for this PR. The deferred OG image needs a screenshot-service route (see above).

Verification

  • node ./scripts/typecheck-strict-changed.js — clean for every file this PR adds or rewrites. The remaining reported errors (CustomFeedOptionsMenu.tsx:51 feeds.edges.length, ProfileActions.tsx user.username) are pre-existing on the base branch; confirmed by reading the same expressions out of origin/claude/website-sharing-visibility-be6b32, untouched by this diff.
  • pnpm --filter shared lint — pass.
  • NODE_ENV=test pnpm --filter shared test — 297 suites / 1997 tests pass.
  • NODE_ENV=test pnpm --filter webapp test — 44 suites / 297 tests pass.
  • pnpm --filter storybook lint not run (missing eslint binary, pre-existing repo issue).
  • build not run, per instructions.

Tests added

  • ProfileShareButton.spec.tsx — copy writes the permalink to the clipboard and raises the ✅ Copied link to clipboard toast; native share calls navigator.share with the share text + link and never touches the clipboard; desktop reveals the network list; both labels (Share your profile / Share @handle's profile) are asserted for a11y.
  • ProfileHeader.spec.tsx — flag-off keeps the invisible edit placeholder and renders no share control; flag-on fills the slot on public profiles and sits beside Edit on the owner's.
  • CustomFeedOptionsMenu.spec.tsxShare is listed with shareProps and dropped without them.

Storybook

Components/Share/ProfileShareButton — public/own labels, network list, copying state, and the button in place in both header variants. HeaderControl is the flag-off story; it holds FeaturesReadyContext as not-ready, because the repo-wide mock/gb.ts coerces a false default to the truthy string 'control' and would otherwise render the variant.

Open questions

  1. Is the pinned-only rule on the mobile bar right? The alternative is showing it in the bar at all times and accepting two copy buttons at the top of a mobile profile. Happy to flip it.
  2. Removing Share from the ... menus — intentional per the brief ("promote out of the menu where it makes sense"), but it does mean the menu loses an entry some users may have learned. Easy to keep both if we'd rather not move anyone's cheese mid-experiment.
  3. Share text for a public profile is Check out {name}'s profile on daily.dev (matching the current menu copy) and Check out my profile on daily.dev for the owner. Worth a copy pass?

🤖 Generated with Claude Code

Preview domain

https://claude-share-profile.preview.app.daily.dev

Adds a dedicated share control to the profile header instead of burying it
in the "..." options menu.

- Own profile: sits next to "Edit profile".
- Public profile: fills the slot the (inapplicable) edit button used to
  reserve, so the layout height is unchanged.
- Stays well away from Follow (different card region, Float icon vs. the
  filled primary CTA) so the two intents don't read as one control group.
- The pinned mobile profile header shows it only while pinned, where the
  profile card has scrolled away — otherwise there would be two identical
  copy buttons on screen.

Built on the shared `ShareActions` primitive from PR 1, so mobile taps
straight through to the native share sheet and desktop opens the network
popover.

Gated by `share_profile` plus the `sharing_visibility` master flag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 22, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
daily-webapp Ready Ready Preview Jul 22, 2026 7:04pm
storybook Building Building Preview Jul 22, 2026 7:04pm

Request Review

Reconciles the CustomFeedOptionsMenu API with the tags/sources branch:
shareProps stays required (no empty-link fallback into useShareOrCopyLink)
and surfaces that promote share to a visible control pass hideShare instead.
File is now byte-identical on both branches so the stack merges cleanly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Evaluate the per-topic flag only once sharing_visibility passes, so control
users are never bucketed into the experiment. Matches the other topic gates.
Also types the menu spec helper now that shareProps is required again.

Co-Authored-By: Claude Opus 4.8 <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