{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "copy-page", "title": "Copy Page", "description": "A copy-to-clipboard button with a dropdown to view the page as Markdown or open it in ChatGPT / Claude.", "dependencies": [ "lucide-react" ], "registryDependencies": [ "https://ds.formance.com/r/button.json", "https://ds.formance.com/r/dropdown-menu.json" ], "files": [ { "path": "registry/default/ui-fragments/copy-page.tsx", "content": "'use client';\n\nimport { Check, ChevronDown, Copy, FileText } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { useState } from 'react';\n\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/registry/default/ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@/registry/default/ui/dropdown-menu';\n\nfunction defaultPrompt(url: string) {\n return `I'm looking at this page: ${url}.\nHelp me understand it. Be ready to explain concepts, give examples, or help debug based on it.`;\n}\n\nconst ChatGPTIcon = () => (\n \n \n \n);\n\nconst ClaudeIcon = () => (\n \n \n \n);\n\nexport type TCopyPageMenuItem = {\n label: string;\n href: string;\n icon?: ReactNode;\n};\n\nexport type TCopyPageProps = {\n /** Text content copied to the clipboard when the main button is clicked. */\n content: string;\n /** Canonical URL of the current page, used for AI prompts and the Markdown link. */\n url: string;\n /** URL exposed by the \"View as Markdown\" item. Defaults to `${url}.md`. */\n markdownUrl?: string;\n /** Extra dropdown items appended after the defaults (e.g. \"View as JSON\"). */\n extraItems?: TCopyPageMenuItem[];\n /** Main button label. Defaults to \"Copy Page\". */\n label?: string;\n /** Prompt sent to ChatGPT / Claude when opening the page in an AI chat. */\n prompt?: string;\n className?: string;\n};\n\nexport function CopyPage({\n content,\n url,\n markdownUrl,\n extraItems = [],\n label = 'Copy Page',\n prompt,\n className,\n}: TCopyPageProps) {\n const [copied, setCopied] = useState(false);\n\n const encodedPrompt = encodeURIComponent(prompt ?? defaultPrompt(url));\n\n const menuItems: TCopyPageMenuItem[] = [\n {\n label: 'Open in Claude',\n href: `https://claude.ai/new?q=${encodedPrompt}`,\n icon: ,\n },\n {\n label: 'Open in ChatGPT',\n href: `https://chatgpt.com?q=${encodedPrompt}`,\n icon: ,\n },\n {\n label: 'View as Markdown',\n href: markdownUrl ?? `${url}.md`,\n icon: ,\n },\n ...extraItems,\n ];\n\n async function handleCopy() {\n await navigator.clipboard.writeText(content);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }\n\n return (\n \n \n \n \n \n \n \n \n \n {menuItems.map(({ label, href, icon }) => (\n \n svg]:size-4 [&>svg]:text-muted-foreground\"\n >\n {icon}\n {label}\n \n \n ))}\n \n \n \n );\n}\n", "type": "registry:component", "target": "components/ui-fragments/copy-page.tsx" } ], "type": "registry:component" }