Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## Unreleased

### Added

- `copy-link` action — copies a link to the current page's Markdown (`.md`) URL to the clipboard. It resolves the same URL the "Open in …" AI actions use (honouring `markdownUrl` / `generateMarkdownRoutes`), so on sites that serve per-page markdown it copies the `.md` link instead of the HTML page URL. Enabled by default; configurable via `enabledActions` and `labels.copyLink`.

## 0.8.3 — 2026-06-17

### Fixed
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ module.exports = {
**Available actions:**
- `'copy'` - Copy page as Markdown
- `'view'` - View as Markdown in new tab
- `'copy-link'` - Copy a link to the page's Markdown (`.md`) URL
- `'chatgpt'` - Open in ChatGPT
- `'claude'` - Open in Claude
- `'perplexity'` - Open in Perplexity
Expand All @@ -225,7 +226,7 @@ module.exports = {
- `'mcp-cursor'` - Install MCP server in Cursor (shown when `mcpServer` is configured)
- `'mcp-vscode'` - Install MCP server in VS Code (shown when `mcpServer` is configured)

**Default:** Standard actions are enabled: `['copy', 'view', 'chatgpt', 'claude', 'perplexity', 'gemini']`. MCP actions are enabled automatically only when `mcpServer` is configured.
**Default:** Standard actions are enabled: `['copy', 'view', 'copy-link', 'chatgpt', 'claude', 'perplexity', 'gemini']`. MCP actions are enabled automatically only when `mcpServer` is configured.

**Example configurations:**

Expand All @@ -237,7 +238,7 @@ enabledActions: ['copy']
enabledActions: ['copy', 'view']

// All standard AI actions (default)
enabledActions: ['copy', 'view', 'chatgpt', 'claude', 'perplexity', 'gemini']
enabledActions: ['copy', 'view', 'copy-link', 'chatgpt', 'claude', 'perplexity', 'gemini']
```

### MCP server actions
Expand Down Expand Up @@ -440,6 +441,7 @@ Available translation IDs:
| `copyPageButton.button.label` | `Copy page` (visible button text) |
| `copyPageButton.copy.title` / `.description` | `Copy page` / `Copy the page as Markdown for LLMs` |
| `copyPageButton.view.title` / `.description` | `View as Markdown` / `View this page as plain text` |
| `copyPageButton.copyLink.title` / `.description` | `Copy link to Markdown` / `Copy this page's .md URL` |
| `copyPageButton.chatgpt.title` / `.description` | `Open in ChatGPT` / `Ask questions about this page` |
| `copyPageButton.claude.title` / `.description` | `Open in Claude` / `Ask questions about this page` |
| `copyPageButton.perplexity.title` / `.description` | `Open in Perplexity` / `Ask questions about this page` |
Expand Down
2 changes: 2 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {CSSProperties} from 'react';
type ActionId =
| 'copy'
| 'view'
| 'copy-link'
| 'chatgpt'
| 'claude'
| 'perplexity'
Expand Down Expand Up @@ -38,6 +39,7 @@ export type CopyPageButtonLabels = {
button?: {label?: string};
copy?: LabelGroup;
view?: LabelGroup;
copyLink?: LabelGroup;
chatgpt?: LabelGroup;
claude?: LabelGroup;
perplexity?: LabelGroup;
Expand Down
2 changes: 2 additions & 0 deletions react.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {ComponentType, CSSProperties} from 'react';
type ActionId =
| 'copy'
| 'view'
| 'copy-link'
| 'chatgpt'
| 'claude'
| 'perplexity'
Expand Down Expand Up @@ -38,6 +39,7 @@ export type CopyPageButtonLabels = {
button?: {label?: string};
copy?: LabelGroup;
view?: LabelGroup;
copyLink?: LabelGroup;
chatgpt?: LabelGroup;
claude?: LabelGroup;
perplexity?: LabelGroup;
Expand Down
31 changes: 30 additions & 1 deletion src/CopyPageButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const {
getMarkdownRouteUrl,
} = require("./htmlToMarkdown");

const DEFAULT_ACTIONS = ['copy', 'view', 'chatgpt', 'claude', 'perplexity', 'gemini'];
const DEFAULT_ACTIONS = ['copy', 'view', 'copy-link', 'chatgpt', 'claude', 'perplexity', 'gemini'];
const DEFAULT_MCP_ACTIONS = ['mcp-copy', 'mcp-cursor', 'mcp-vscode'];
const POSITIONING_PROPS = ['position', 'top', 'right', 'bottom', 'left', 'zIndex', 'transform'];
const DROPDOWN_WIDTH = 300;
Expand Down Expand Up @@ -241,6 +241,16 @@ export default function CopyPageButton({
return generateMarkdownRoutes ? getMarkdownRouteUrl(pageUrl) : pageUrl;
};

// Copy a link to the current page's markdown to the clipboard. Resolves the
// same URL the "Open in ChatGPT/Claude/…" actions reference, so on sites that
// serve per-page markdown this copies the `.md` link rather than the HTML one.
const copyMarkdownLink = async () => {
if (typeof window === "undefined") {
return;
}
await writeTextToClipboard(resolveContextUrl(window.location.href));
};

// Notify host-site analytics whenever a dropdown action runs, so maintainers
// can measure how the button is used. Pairs with the `data-copy-page-action`
// attributes for sites that prefer delegated DOM listeners.
Expand Down Expand Up @@ -409,6 +419,25 @@ Please provide a clear summary and help me understand the key concepts covered i
),
action: viewAsMarkdown,
},
{
id: "copy-link",
title: t("copyLink", "title", "Copy link to Markdown"),
description: t("copyLink", "description", "Copy this page's .md URL"),
icon: (
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
>
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
</svg>
),
action: copyMarkdownLink,
},
{
id: "chatgpt",
title: t("chatgpt", "title", "Open in ChatGPT"),
Expand Down