import { Button } from '@/components/button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/dropdown-menu'; import { CopyIcon, DocumentIcon, ShareBoxIcon, ShareIcon } from '@/icons'; import { useMessages } from '~/i18n'; import type { Entry } from '~/registry/types'; import { absoluteHref, useRoute } from '~/router'; import { useCopy } from '../hooks/use-copy'; /** * Share the instance in front of you. * * The copy buttons hand out code; this hands out the *view*. Because * `chrome/lib/prop-params.ts` keeps the playground's bag in the hash, the current * URL already describes the configured component down to the last axis — so the * page link is `location.href` and there is nothing to serialise. * * The second link is the point of the embed route: a colleague who is not going * to read a props table gets the component alone on a page, at the theme and * language you were looking at, with no rail and no toolbar around it. * * Kit components throughout, per the rule at the top of `playground.tsx` — this * is chrome, not a control that drives the component under test. */ export function ShareButton({ entry, snippet, }: { entry: Entry; /** * The import line and JSX for what is on screen, as a thunk. * * The playground already has that snippet under the preview, but the two * audiences meet here: someone who opens this menu to send a teammate a link * usually wants to paste the component into a message too, and a menu that * makes them close it and scroll to a second button for that is a menu that * knows less than it should. Deferred to the click for the same reason * `CopyButton` defers — nothing serialises a tree nobody asked for. */ snippet: () => string; }) { const m = useMessages(); const { path, params } = useRoute(); /* Two hooks, because the toast wording is the whole point of `useCopy`'s argument: "Link copied" over a pasted JSX block would be a lie. */ const [, copyLink] = useCopy(m.share.linkCopied); const [, copyCode] = useCopy(); const pageUrl = absoluteHref(path, params); const embedUrl = absoluteHref(`/embed/${entry.slug}`, params); return ( {/* `align="end"` because the trigger sits at the right edge of the section header; the menu opening leftwards keeps it inside the column. */} copyLink(pageUrl)}> {m.share.copyLink} copyLink(embedUrl)}> {m.share.copyPreview} {/* The same string the block under the preview copies — one funnel through `chrome/lib/codegen.ts`, so the menu cannot hand out a snippet that differs from the one on the page. */} copyCode(snippet())}> {m.share.copyCode} {/* A real anchor rather than `window.open`: middle-click, "open in new window" and a copied target all come free, and a popup blocker has nothing to block. */} {m.share.openPreview} ); }