Add Copy as Markdown actions to each page - #70
Merged
Conversation
The llmstxt plugin already writes a .md counterpart for every page, but reaching it meant knowing the URL. This surfaces it: a "Copy as Markdown" button that fetches the file and puts it on the clipboard, and a "View Markdown" link beside it. Retype ships this as doc-page-actions; Material does not, and the request for it (squidfunk/mkdocs-material#8382) sits on their backlog, so it is built here. The target URL is derived in JavaScript from the current path rather than rendered into the template, since use_directory_urls is false and it is only the extension that differs. The controls start hidden and are revealed only after a HEAD request confirms the file exists, so they never appear on a page the plugin does not cover. Verified by removing a .md from the built site and loading the page in headless Chrome: the container keeps its hidden attribute. On a normal page the attribute is dropped and the link resolves correctly. Binding goes through Material's document$ observable, with a DOMContentLoaded fallback, so enabling navigation.instant later will not silently break it. Also excludes overrides/ from the docs collection. custom_dir points inside docs/, so mkdocs was copying the theme template into the site as a page and serving raw Jinja at /overrides/main.html. That predates this change; it is fixed here because it is the same file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds the equivalent of what camoufox.com offers, on top of the
.mdfiles from #69.What camoufox actually does
It runs Retype, which renders a
<doc-page-actions>component and exposes each page as Markdown:Material has no equivalent. squidfunk/mkdocs-material#8382 asked for exactly this and was closed as a duplicate in August 2025, with the maintainer putting it on the backlog pending the end of feature freeze. So it is built here.
The feature
Two controls at the top right of every page:
.mdand writes it to the clipboard, with the label switching to "Copied" for two seconds#69 supplies the files; this makes them reachable without knowing the URL scheme.
Design notes
The URL is derived in JavaScript, not the template.
use_directory_urlsis false, so pages arepage.htmland their Markdown ispage.md— only the extension differs. Deriving it at runtime keeps the template free of path logic.The controls start hidden. A
HEADrequest confirms the file exists before they are revealed, so they never appear on a page the plugin does not cover. Every page currently has one, so this is defensive — but it means adding a page outside the llmstxt sections degrades quietly instead of shipping a broken button.Binding goes through Material's
document$observable, with aDOMContentLoadedfallback.navigation.instantis not enabled today; if it is enabled later, this keeps working rather than silently binding once.Verification
Built the site and drove it in headless Chrome against a local server.
On a normal page the
hiddenattribute is dropped and the link resolves:With the
.mdremoved from the built site, the controls stay hidden:URL derivation checked across page shapes — API, notebook, quick-start, releases, and the site root all resolve to a file served with HTTP 200. The button renders on all 26 content pages; Material's
404.htmldoes not use this template block, so it is excluded naturally.One thing not verified end to end: the clipboard write itself.
navigator.clipboardneeds a secure context and a permission grant that headless Chrome does not give by default. The fetch path either side of it is confirmed, and the failure branch sets a "Copy failed" label rather than doing nothing.Adjacent fix
custom_dir: docs/overridespoints insidedocs/, so mkdocs was also copying the theme template into the site as a page — visitors hitting/overrides/main.htmlgot raw Jinja. This predates the change;exclude_docs: overrides/stops it, and it is fixed here because it is the same file.Possible follow-up
Sites like Anthropic's and Mintlify's add "Open in ChatGPT" / "Open in Claude" entries alongside the copy button, which deep-link to those services with the page URL prefilled. Left out — it adds external service links, which is a product decision rather than a technical one.