Expose per-page Markdown actions on the docs site#715
Expose per-page Markdown actions on the docs site#715dahlia wants to merge 8 commits intofedify-dev:mainfrom
Conversation
Add a compact per-page Markdown action to the docs so readers can open or copy the generated Markdown for the current page without guessing the output path. Adjust the docs site integration so the action sits alongside page titles, behaves safely in the dev server, and keeps llms.txt and llms-full.txt curated by excluding high-noise pages. Closes fedify-dev#706 Assisted-by: Codex:gpt-5.4
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a per-page Markdown UI to the docs site, refactors the Changes
Sequence Diagram(s)sequenceDiagram
participant Reader as Reader (Browser)
participant Component as PageMarkdownActions
participant DocsServer as VitePress Server
participant Clipboard as Clipboard API
Reader->>Component: Click "View as Markdown"
Component->>Component: compute markdown URL from route.path
Component->>DocsServer: open markdown URL (new tab)
DocsServer-->>Reader: serve generated .md file
Reader->>Component: Click "Copy Markdown"
Component->>Component: compute markdown URL
Component->>DocsServer: fetch markdown text
DocsServer-->>Component: return markdown text (or dev notice)
alt Dev server / unavailable
Component-->>Reader: show alert "Unavailable in dev server"
else Available
Component->>Clipboard: navigator.clipboard.writeText(markdown)
Clipboard-->>Component: success / failure
Component-->>Reader: show "Copied" or "Copy failed" feedback
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces a per-page Markdown action to the documentation site, allowing users to view or copy the LLM-friendly Markdown for any page. Key changes include the addition of the PageMarkdownActions component, theme integration, and updated llmstxt plugin configuration. Review feedback identifies critical issues in the new component, such as a potential SSR crash caused by DOM access during the build process, a reactivity bug where the Markdown path does not update during navigation, and incorrect path resolution for index pages. A style guide violation regarding file name formatting in the changelog was also noted.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/.vitepress/theme/components/PageMarkdownActions.vue`:
- Around line 69-87: The copyMarkdown function can leave copied.value true when
a later failure occurs (so the UI still shows "Copied"); in the catch block
reset copied.value to false and clear or cancel any pending success timer so
copyFailed takes effect; locate copyMarkdown and update the catch handling to
set copied.value = false (and clear the timeout used when setting copied.value
true) before setting copyFailed.value = true and starting its timeout.
- Around line 15-56: The code sets path only once in onMounted and registers the
watch outside of onMounted which causes stale markdown path and DOM access
before mount; change path to be a computed based on route.path (use computed(()
=> /* derive .md from route.path like current path logic */)) and replace usages
of path with this computed (markdownPath), and move the watch(...) call that
calls ensureTarget() into onMounted so ensureTarget() runs only after mount;
keep the ensureTarget() function unchanged but reference it from the
onMounted-initialized watcher and update any existing markdownPath variable
usage to the new computed one.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 0ad09e6e-4d74-479b-9a65-fbfc9012680b
📒 Files selected for processing (5)
CHANGES.mddocs/.vitepress/config.mtsdocs/.vitepress/theme/components/PageMarkdownActions.vuedocs/.vitepress/theme/index.tsdocs/.vitepress/theme/style.css
Codecov Report✅ All modified and coverable lines are covered by tests. 🚀 New features to boost your workflow:
|
Make the docs Markdown action follow VitePress route changes, avoid DOM work before mount, and handle index-style page paths correctly. This keeps the action pointed at the current page and prevents stale UI state after copy failures. fedify-dev#715 (comment) fedify-dev#715 (comment) fedify-dev#715 (comment) Assisted-by: Codex:gpt-5.4
Format *README.md* in the changelog entry so the docs section follows the repository's Markdown file path style. fedify-dev#715 (comment) Assisted-by: Codex:gpt-5.4
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/.vitepress/theme/components/PageMarkdownActions.vue`:
- Line 115: The v-if on the Teleport uses a dead null check against the computed
markdownPath which always returns a string; remove the redundant "markdownPath
!= null &&" and leave only "targetReady" in the Teleport v-if (locate the
Teleport element in PageMarkdownActions.vue and the computed named markdownPath
to confirm behavior) so the conditional reflects only the meaningful guard.
- Around line 107-111: The viewMarkdown handler currently returns early in
production so the details dropdown stays open; change viewMarkdown(event) to
handle both dev and prod: if isDev keep the preventDefault() +
alert(devMessage), otherwise allow the link action and call closeMenu(event) so
the dropdown closes after navigation (or call closeMenu(event) after
window.open/navigation if you open a new tab manually). Also update copyMarkdown
to call closeMenu(event) at the end of its successful branch so the menu closes
after a successful copy; refer to the viewMarkdown, copyMarkdown and closeMenu
function names to locate the changes.
- Around line 22-55: ensureTarget() currently mutates the VitePress-rendered
<h1> and can pick up a stale or missing element after SPA navigation; modify
updateTarget/ensureTarget to wait reliably for the new .vp-doc h1 by adding a
retry strategy (e.g., loop with requestAnimationFrame or attach a scoped
MutationObserver to .vp-doc that resolves when an h1 appears) instead of relying
solely on nextTick(), and ensure you clean up any created wrapper/target on
unmount by moving wrapper/target creation into a stable Vue-managed element or
removing the created .page-title-row and .page-title-actions-target in an
onBeforeUnmount handler; reference ensureTarget(), updateTarget(), onMounted()
and targetReady when making these changes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 189311f0-1074-469c-8b9a-2dc4f61915e8
📒 Files selected for processing (2)
CHANGES.mddocs/.vitepress/theme/components/PageMarkdownActions.vue
Make the docs Markdown dropdown wait for the current page heading, clean up its injected title wrapper on unmount, and close the menu after actions so repeated navigation leaves no stale open state. fedify-dev#715 (comment) fedify-dev#715 (comment) fedify-dev#715 (comment) Assisted-by: Codex:gpt-5.4
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/.vitepress/theme/components/PageMarkdownActions.vue`:
- Line 16: The title DOM is not restored before each route retarget which lets a
VitePress-rendered <h1> be trapped in a non-Vue wrapper and allows stale async
updateTarget completions to reattach old nodes; modify the component logic so
that ensureTarget() first calls cleanupTarget() (or an explicit unwrapTitle()
helper) to restore the current heading DOM before reparenting, and add a
cancellation/version token (e.g., incrementing requestId or using an AbortToken
checked in updateTarget's async path) so older async completions ignore and do
not retarget the DOM after a newer route change; update references in
PageMarkdownActions.vue to use the same token in ensureTarget(), updateTarget(),
and cleanupTarget() to locate and fix the behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: e3085149-92cc-4bd8-8bd3-559e25ad5b43
📒 Files selected for processing (1)
docs/.vitepress/theme/components/PageMarkdownActions.vue
Prevent stale async title retargeting from older route updates, restore the wrapped heading before each new retarget, and invalidate pending work during unmount. This same pass also makes copy failures distinguish between Markdown load problems and clipboard write failures. fedify-dev#715 (comment) Assisted-by: Codex:gpt-5.4
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/.vitepress/theme/components/PageMarkdownActions.vue`:
- Around line 91-99: The SPA navigation can let a pending copy promise from the
previous page set stale feedback; update updateTarget() (which increments
targetUpdateVersion and calls ensureTarget) to also reset copied and copyFailed
refs (set copied.value = false and copyFailed.value = false) when retargeting,
and in the copy handler capture the current targetUpdateVersion at start and
before setting copied.value or copyFailed.value verify the captured version
matches targetUpdateVersion so stale async completions are ignored; reference
updateTarget(), targetUpdateVersion, copied, copyFailed and the copy handler to
locate and apply the changes (also apply the same resets/checks in the other
retargeting region around lines 143–179).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: aa291ef4-2cd5-4caf-afd1-1bd434572e69
📒 Files selected for processing (1)
docs/.vitepress/theme/components/PageMarkdownActions.vue
Reset copy feedback when the docs page retargets and ignore clipboard results that complete after a newer route update. This keeps copy status messages from leaking across VitePress SPA navigation. fedify-dev#715 (comment) Assisted-by: Codex:gpt-5.4
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/.vitepress/theme/components/PageMarkdownActions.vue`:
- Around line 145-175: The post-await call to closeMenu in copyMarkdown is a
no-op because event.currentTarget is cleared after awaiting; fix by capturing
the actionable element (e.g., const trigger = (event.currentTarget as
HTMLElement | null) or the details element) before any await and pass that
captured element into closeMenu after the awaits, or alternatively change
closeMenu to accept an HTMLElement/details element and update viewMarkdown to
pass event.currentTarget the same way so both handlers consistently call
closeMenu with the element instead of relying on event after async awaits;
update references in copyMarkdown, viewMarkdown, and closeMenu accordingly (also
note getMarkdown and navigator.clipboard.writeText remain awaiting operations).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 3387ae55-4d55-479c-b177-bbf11a4ca1bf
📒 Files selected for processing (1)
docs/.vitepress/theme/components/PageMarkdownActions.vue
Capture the dropdown trigger before awaiting Markdown fetch and clipboard writes so the menu still closes after a successful copy. This avoids relying on event.currentTarget after async suspension. fedify-dev#715 (comment) Assisted-by: Codex:gpt-5.4
|
Pre-release has been published for this pull request: DocumentationThe docs for this pull request have been published: |
Leave the docs Markdown dropdown open after a successful copy so readers can actually see the copied state feedback. Viewing the page as Markdown still closes the menu, but copy now favors immediate UI confirmation over collapsing the dropdown. Assisted-by: Codex:gpt-5.4
Preview it at https://pr-715.fedify.pages.dev/intro.
Closes #706.
Summary
llms.txtandllms-full.txtfocused by excluding high-noise pages such as the changelog, contribution guide, README, and sponsors page, while still exposing per-page Markdown actions on those pages.Background
The docs build was already generating per-page Markdown through
vitepress-plugin-llms, but there was no obvious way to reach it from a documentation page itself. In practice, that meant readers had to know aboutllms.txtahead of time or guess the generated*.mdURL by hand.This change adds a visible page-level entry point for that Markdown representation while preserving the existing docs layout and keeping the global LLM-oriented indexes selective.
Implementation notes
h1headings do not collide with the control.llms.txtandllms-full.txtcurated with per-output exclusions instead of hiding the affected pages from per-page Markdown entirely.Testing