Skip to content

feat(share): briefing copy actions + personalized digest share parity - #6353

Open
tsahimatsliah wants to merge 5 commits into
claude/website-sharing-visibility-be6b32from
claude/share-briefing-digest
Open

feat(share): briefing copy actions + personalized digest share parity#6353
tsahimatsliah wants to merge 5 commits into
claude/website-sharing-visibility-be6b32from
claude/share-briefing-digest

Conversation

@tsahimatsliah

@tsahimatsliah tsahimatsliah commented Jul 22, 2026

Copy link
Copy Markdown
Member

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

A presidential briefing is one of the most shareable things daily.dev produces, and there was almost nowhere to share it from: the briefing list had no copy affordance, the header had a single desktop-only copy-link button, the briefing body had none at all, and the personalized digest — which renders the same header component — had nothing whatsoever.

What changed

1. /briefing rows (BriefListItem.tsx) — copy-link and a share arrow at the end of each row.

2. Inside the briefing body (new BriefContent.tsx) — the body is a single sanitized-HTML blob from Markdown, so there was no per-item affordance: the only way to share one finding was to select text by hand. BriefContent wraps Markdown, appends a mount node to every heading, bullet and paragraph, and portals a copy control into it.

A bullet or paragraph copies its own text; a heading copies its whole section — heading, prose, then one bullet per line — stopping at the next heading. The selector is deliberately wide (h1h4, li, standalone p): the body is model-generated, so heading level and bullets-vs-prose vary between briefings, and matching only h2/h3/li left some briefs with no controls at all. Controls are dimmed at rest and come to full strength on hover or focus — never hover-only, which is undiscoverable on a mouse and unreachable on touch.

3. Post header (BriefPostHeaderActions.tsx) — the same copy + share pair, outside the hidden laptop:block wrapper, since sharing a briefing matters at least as much on mobile. Copy link is its own control rather than living only inside the popover: it is the most common action and should not cost two taps.

4. Digest parity (DigestPostContent.tsx) — it rendered the identical header component with showShareButton omitted, so it had no share affordance. Now passes it, gated. While making it a changed file the strict-typecheck guard surfaced its pre-existing strict-null backlog, fixed by mirroring BriefPostContent. No behaviour change.

Icon language

The share trigger, the copy-link control and the copy-text actions all rendered a copy or link glyph, so "share" and "copy" were indistinguishable. Settled to one glyph per meaning:

Glyph Means
arrow (ShareIcon) opens a share surface — popover on desktop, native sheet on mobile. Never a one-tap copy.
link copies the bare URL
stacked squares (CopyIcon) copies text, with the link appended
page (DocsIcon) copies the generated summary

Every text copy appends the briefing link, so a paste into Slack is quotable and still carries attribution.

Copy confirmation

Every control confirms with the design system's success checkmark (VIcon / text-status-success) for 1s, and toasts use ToastType.Success so the chip carries the same check.

New useCopyFeedback hook: useCopy already exposes a copying flag, but there is one per hook instance — the controls inside a briefing share one, so using it directly would light them all at once. The hook tracks which control fired.

Structure

  • BriefShareControls.tsx holds the copy + share pair and the standalone copy-link button, used by both the row and the header so the two surfaces cannot drift.
  • The row originally grouped its actions behind a dropdown. With no summary that collapsed to two near-identical "copy" entries — more chrome than the controls it hid — so it now shows both directly and the menu component is gone.

Layout fix

base.css sets a global * { flex-shrink: 0 }, so the row's text column kept its w-full width and refused to shrink: the trailing control painted ~100px outside the card border on every row, not just long titles. min-w-0 flex-1 restores a shrinkable basis and the title truncates. Measured 0px overflow at 640/480/360px.

Flag

share_briefing_digest, default false, resolved by useShareBriefingDigest, which also requires the master useSharingVisibility() gate.

Flag-off is identical to PR 1, asserted in Jest: the row renders no interactive controls, the header keeps its legacy copy-link button, the body renders exactly as today, and the digest exposes nothing.

Testing on the preview: both sharing_visibility and share_briefing_digest must be enabled in GrowthBook. With the defaults the preview shows the control experience.

Storybook

stories/components/BriefSharing.stories.tsx — every state of all four surfaces, each in flag-on and flag-off form, plus an Overview mapping them on one page and an IconLanguage story documenting the vocabulary.

Two notes for reviewers:

  • useConditionalFeature reads GrowthBook through FeaturesReadyContext + GrowthBookContext. With neither mounted — Storybook's default — every flag resolves to its defaultValue, i.e. off. (The 'control'-returning mock in .storybook/main.ts applies to useFeature, not this path.) A small FeatureGate provider pins flags per story, which the header needs since it reads the gate directly and has no override prop.
  • The Toast renderer is mounted in the decorator. Copy actions already toasted through useCopy, but Storybook never rendered it, so the confirmation was invisible there.

OG image — deferred, deliberately

Not shipped. packages/webapp/pages/image-generator/ pages are plain Next.js pages that a backend screenshot service renders and captures. A briefing OG image needs that service taught a new route plus an ISR data path for brief posts — a backend dependency that cannot land from this repo alone.

Verification

  • node ./scripts/typecheck-strict-changed.js — passed
  • pnpm --filter shared lint — clean
  • NODE_ENV=test pnpm --filter shared test — 296 suites / 2004 tests
  • NODE_ENV=test pnpm --filter webapp test — 44 suites / 297 tests
  • NODE_ENV=test pnpm --filter extension test — 6 suites / 43 tests

Tests cover both copy payloads and the section boundary, the wide selector against an h1/h4 prose-only brief, the nested-paragraph case, the checkmark appearing only on the clicked control and clearing after its window, logging discriminators per item kind, and flag-off rendering nothing.

🤖 Generated with Claude Code

Preview domain

https://claude-share-briefing-digest.preview.app.daily.dev

@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 29, 2026 7:27am
storybook Building Building Preview Jul 29, 2026 7:27am

Request Review

@tsahimatsliah

Copy link
Copy Markdown
Member Author

⚠️ 6cf22f33b must be reverted before merge.

The preview deploy resolves share_briefing_digest to its false default, so none of this PRs surfaces were testable there — isDevelopment is false in a Vercel preview build, so the documented local escape hatch does not reach it. That commit adds a FORCE_ON_FOR_PREVIEW constant in useShareBriefingDigest.ts purely so the preview is reviewable.

The flag default in featureManagement.ts is untouched and stays false. To restore the real gate, delete the constant and its use in the return — nothing else changes.

git revert 6cf22f33b

A presidential briefing is one of the most shareable things daily.dev
produces, and there was almost nowhere to share it from: the briefing list
had no copy affordance, the header had a single desktop-only copy-link
button, the briefing body had none at all, and the personalized digest —
which renders the same header component — had nothing.

- `/briefing` rows gain copy-link and a share arrow.
- The briefing body gains a copy control on every heading, bullet and
  paragraph. `BriefContent` wraps `Markdown`, appends a mount node per item
  and portals a control in, since the body is one sanitized-HTML blob. A
  heading copies its whole section; every copy appends the briefing link so
  a paste stays attributed.
- The post header gains the same copy + share pair, outside the laptop-only
  wrapper so it works on mobile.
- `DigestPostContent` passes `showShareButton`, reaching parity with the
  brief.

One glyph per meaning across all of it: arrow opens a share surface, link
copies the bare URL, stacked squares copy text with the link appended, page
copies the summary. Every control confirms with the design system's success
checkmark and a `ToastType.Success` toast.

Also fixes a pre-existing layout bug: `base.css` sets a global
`* { flex-shrink: 0 }`, so the row's `w-full` text column refused to shrink
and painted trailing controls ~100px outside the card on every row.

Gated by `share_briefing_digest`, which also requires the master
`sharing_visibility` kill-switch. Flag-off is identical to PR 1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tsahimatsliah
tsahimatsliah force-pushed the claude/share-briefing-digest branch from bc27c9d to 06d9043 Compare July 28, 2026 08:16
@tsahimatsliah

Copy link
Copy Markdown
Member Author

Rebuilt as a single clean commit on top of PR 1. The temporary FORCE_ON_FOR_PREVIEW override is goneuseShareBriefingDigest resolves the real gate again, so there is nothing left to revert before merge.

Consequence for preview testing: sharing_visibility and share_briefing_digest both need enabling in GrowthBook, otherwise the preview shows the control experience.

…ORE MERGE

The preview deploy resolves `share_briefing_digest` to its `false` default,
so none of this PR's surfaces render there. `isDevelopment` is false in a
Vercel preview build (NODE_ENV is `production`), so the documented local
escape hatch does not reach it.

Isolated in its own commit on purpose: `git revert` restores the real gate
and leaves the feature commit untouched. The flag default in
`featureManagement.ts` stays `false`.

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

Copy link
Copy Markdown
Member Author

7441c0f68 re-adds the preview override — the /mockup-to-eng pass removed it as scaffolding, which also made the feature invisible on the preview deploy.

It sits in its own commit on top of the feature commit, so git revert 7441c0f68 restores the real gate and leaves 06d90436f untouched. The flag default stays false.

Revert before merge.

A briefing should read as prose, not as a grid of affordances. The
controls inside the body now sit at `opacity-0` and are revealed by
hovering their own item.

Touch has no hover, so coarse pointers still get them outright, and
keyboard focus reveals them too — otherwise the feature would be
unreachable in both. The control stays pinned while confirming so the
checkmark survives the pointer leaving as the click lands.

Scoped to `BriefContent`: the `/briefing` row and the post header keep
their always-visible controls, since those are single controls on a card
rather than one per line of prose.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The link riding along with every in-briefing copy was `post.commentsPermalink`
raw, while every other share surface copies a tracked, shortened URL built
with `ReferralCampaignKey.SharePost`. These were the only shares in the app
going out uncredited — traffic from a pasted bullet was attributed to nobody.

Resolved through `useGetShortUrl` up front rather than awaited in the click
handler: awaiting there would put the clipboard write outside the user
gesture, which browsers can block. `getTrackedUrl` covers the logged-out and
still-loading cases.

Also spreads `logOpts` from `ActiveFeedContext` on the briefing share events,
matching `usePostContent`, `SocialShare` and `ShareBar`, so a brief or digest
opened as a feed modal carries grid position like every other post share. It
is a no-op on `/briefing`, which provides no `logOpts`.

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

@capJavert capJavert left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review complete. Blocking before merge: useShareBriefingDigest still contains FORCE_ON_FOR_PREVIEW = true, which bypasses both sharing_visibility and share_briefing_digest for every environment. Revert commit 7441c0f68 as documented before this can be approved. I found no merge conflict; the PR is currently clean against its stacked base.

@tsahimatsliah
tsahimatsliah marked this pull request as ready for review July 29, 2026 06:47
@tsahimatsliah

Copy link
Copy Markdown
Member Author

@capJavert Fixed in 616015d05 — a straight git revert 7441c0f68.

You were right, and more right than my own commit message was. I labelled it "for preview", but return FORCE_ON_FOR_PREVIEW || (...) has no environment condition in it at all — it short-circuits to true everywhere, so on merge it would have shipped the initiative to 100% of users and made the sharing_visibility kill-switch inert. Not a preview-only hack, a production one.

useShareBriefingDigest is back to:

return isSharingVisible && value;

grep -rn "FORCE_ON_FOR_PREVIEW\|TEMP-REVIEW" across packages/shared, packages/storybook and packages/webapp returns nothing, so no scaffolding is left anywhere.

Why it existed, for context: share_briefing_digest defaults to false, and isDevelopment is false in a Vercel preview build (NODE_ENV is production there), so the documented local escape hatch does not reach the preview — none of the surfaces render there without a GrowthBook override. That is a testing-workflow problem and it should not have been solved in the source. Anyone reviewing the preview now needs sharing_visibility and share_briefing_digest enabled in GrowthBook.

Verified after the revert: shared 296 suites / 2004 tests, webapp 44 / 297, strict typecheck and lint_shared clean.

Two things in this PR that are additive to analytics and worth a heads-up rather than a change:

  • ShareProvider.CopyText (copy text) is a new provider value; nothing else emits it
  • extra.content (brief_bullet / brief_paragraph / brief_section) is a new key

Existing dashboards will not break, but they will not include these copies until the filters are widened. Happy to rename either if you would prefer they fold into an existing value.

@capJavert capJavert left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed after 616015d. The unconditional preview override is fully reverted and both sharing gates are effective again. I found no remaining code blocker. Approved against the stacked base; merge sequencing still depends on #6343.

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.

2 participants