Skip to content

feat(share): copy-my-feed digest button in the feed nav#6362

Draft
tsahimatsliah wants to merge 1 commit into
claude/website-sharing-visibility-be6b32from
claude/share-copy-my-feed
Draft

feat(share): copy-my-feed digest button in the feed nav#6362
tsahimatsliah wants to merge 1 commit into
claude/website-sharing-visibility-be6b32from
claude/share-copy-my-feed

Conversation

@tsahimatsliah

@tsahimatsliah tsahimatsliah commented Jul 22, 2026

Copy link
Copy Markdown
Member

Part of the sharing-visibility initiative (builds on PR 1, #6343). Adds a "Copy my feed" button to the feed navigation that generates a copyable text digest of the top ~20 posts from the current feed.

What changed

  • CopyMyFeedButton (packages/shared/src/components/feeds/CopyMyFeedButton.tsx): icon-only Tertiary button (tooltip + aria-label, type="button"), disabled while the active feed has no loaded posts, renders null while the flag is off.
  • Placement — the two feed-nav surfaces this PR owns:
    • Phones: MobileFeedActions right-side action row (next to quests/giveback).
    • Tablets: the FeedNav corner overlay (JS-gated with isTablet like the giveback entry, so phones never mount a hidden duplicate). The last tab's clearance margin bumps mr-24 → mr-36 only when the flag is on, following the precedent from the giveback entry (7689803).
    • Note: FeedNav only renders below laptop (MainLayoutHeader gates it with isMobile). The laptop+ feed header lives in MainFeedLayout.tsx, which sibling PR 16 owns — a desktop placement is intentionally left out of this PR (see below).
  • useCopyMyFeed: reads the posts straight from the TanStack Query cache — no duplicate feed request. Feed queries are keyed [feedName, userId, ...variables] (generateQueryKey + MainFeedLayout), so the hook prefix-matches [activeFeedName, userId] (plus [custom, userId, defaultFeedId] for the custom-default-feed-on-/ case) and digests the newest matching query with data. Button enablement subscribes to the query cache via useSyncExternalStore with a cheap primitive snapshot (dataUpdatedAt), gated off entirely while the flag is off.
  • Digest format (dev-pastes-it-in-Slack voice):
    My daily.dev feed today:
    
    • {title} {trackedLink}
    
    Capped at 20 posts across loaded pages, deduped by id, highlight/ad items skipped. If fewer than 20 posts are loaded we copy what's there — no forced fetching.
  • Behavior: mobile → native share sheet (navigator.share({ text }), feature-detected via shouldUseNativeShare); otherwise copy to clipboard + toast.
  • Logging: generic LogEvent.ShareLog with extra: { origin: Origin.CopyMyFeed, provider, postCount } (one event per entity, no per-surface event). Origin.CopyMyFeed comes from PR 1.
  • Storybook: CopyMyFeedButton.stories.tsx — loaded-feed state with a preview of the exact composed text, empty-feed (disabled), flag-off control (renders nothing, simulated by holding FeaturesReadyContext not-ready since the Storybook GB mock can't evaluate false), and a clipboard interaction play test.

Tracked-link approach: long links, not short links

Per-link shortening would cost ~20 sequential GraphQL calls per copy, so links go through addLogQueryParams-style tracked long links instead (getTrackedUrl with the new ReferralCampaignKey.CopyMyFeed?userid=…&cid=copy_my_feed). Tradeoff: URLs are longer/uglier than dly.to links, but the copy is instant and attribution is preserved.

Flag

share_copy_my_feed, default false, appended at the end of featureManagement.ts. Gated together with the sharing_visibility master switch via useConditionalFeature + shouldEvaluate (the per-topic flag is only evaluated once the master is on). Flag-off renders nothing — nav DOM/pixels identical to the base branch, asserted in Jest.

Verification

  • node ./scripts/typecheck-strict-changed.js — pass
  • pnpm --filter shared lint — pass (0 warnings)
  • NODE_ENV=test pnpm --filter shared test — 295 suites, 1993 tests, all pass
  • NODE_ENV=test pnpm --filter webapp test — 44 suites, 297 tests, all pass
  • New tests assert: digest contains titles + tracked links of loaded posts; 20-post cap across pages; copy → clipboard + toast + ShareLog(provider=copy link, postCount); mobile → navigator.share with the digest text + ShareLog(provider=native); empty feed → disabled button, no copy; flag-off → empty DOM (component spec) and unmocked-flag-off surface assertion in MobileFeedActions.spec.tsx.

🤖 Generated with Claude Code

Preview domain

https://claude-share-copy-my-feed.preview.app.daily.dev

Adds a "Copy my feed" button to the mobile feed nav (MobileFeedActions on
phones, the FeedNav tablet corner on tablets) that copies — or natively
shares on mobile — a Slack-pasteable text digest of the top 20 posts
already loaded in the active feed, one bullet per post with a tracked
link.

The digest is read straight from the TanStack Query cache by
prefix-matching the feed query key ([feedName, userId, ...variables]),
so no duplicate feed request is ever fired; if fewer than 20 posts are
loaded we copy what's there. Links are tracked long links via
addLogQueryParams (cid=copy_my_feed) rather than short links, since
shortening 20 URLs would cost 20 network calls per copy.

Gated behind the new share_copy_my_feed flag (default false) together
with the sharing_visibility master switch — flag-off renders nothing and
the nav chrome stays pixel-identical. Logs the generic ShareLog event
with origin "copy my feed", provider, and postCount.

Co-Authored-By: Claude Fable 5 <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 Error Error Jul 22, 2026 4:23pm
storybook Building Building Preview Jul 22, 2026 4:23pm

Request Review

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