Skip to content

🔧 fix: change markdown button to copy to clipboard#777

Open
Aqua-123 wants to merge 1 commit intoelysiajs:mainfrom
Aqua-123:fix/copy-markdown-to-clipboard
Open

🔧 fix: change markdown button to copy to clipboard#777
Aqua-123 wants to merge 1 commit intoelysiajs:mainfrom
Aqua-123:fix/copy-markdown-to-clipboard

Conversation

@Aqua-123
Copy link

@Aqua-123 Aqua-123 commented Jan 7, 2026

Summary

  • Changed the "Open in Markdown" button to copy the page's markdown content to clipboard instead of opening in a new tab

Changes

  • Converted the markdown link to a element
  • Added copyMarkdownToClipboard() async function that:
    • Fetches the markdown content from the current page's .md URL
    • Copies it to the user's clipboard using the Clipboard API
    • Handles errors gracefully with console logging
  • Updated button title from "Open in Markdown" to "Copy as Markdown" to reflect the new behavior

Why

This makes it easier for users to quickly grab the markdown content for use in AI tools like ChatGPT or Claude without having to navigate to a new tab and manually copy the content.

Summary by CodeRabbit

Release Notes

  • New Features
    • Replaced the "Open in Markdown" link with a "Copy as Markdown" button that copies the current page's Markdown content directly to your clipboard for easy sharing and offline access.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 7, 2026

Walkthrough

The layout component now copies page Markdown to clipboard via a new button instead of opening it in a new tab. A copyMarkdownToClipboard() function fetches and copies the Markdown with error handling.

Changes

Cohort / File(s) Summary
Markdown Copy Feature
docs/.vitepress/theme/layout.vue
Replaces anchor link with button that triggers copy-to-clipboard workflow; adds copyMarkdownToClipboard() function that fetches page Markdown from derived URL and copies to clipboard with error handling; updates UI label from "Open in Markdown" to "Copy as Markdown"

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A button hops where links once played,
Clipboard magic, no new tab made!
Fetch and copy with graceful care,
Markdown awaits, light as spring air! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: converting a markdown button from opening a link to copying markdown to clipboard.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
docs/.vitepress/theme/layout.vue (1)

200-206: LGTM! Semantic improvement from link to button.

The conversion from <a> to <button> is semantically correct—buttons should trigger actions (copy), while links navigate. The title update clearly communicates the new behavior.

Optional: Add explicit type="button"

As a defensive best practice, explicitly set type="button" to prevent potential form submission if the component is ever used in a form context:

 <button
     @click="copyMarkdownToClipboard"
     class="clicky"
     title="Copy as Markdown"
+    type="button"
 >
     <File stroke-width="1.5" />
 </button>
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e81c437 and 36ef2d5.

📒 Files selected for processing (1)
  • docs/.vitepress/theme/layout.vue

Comment on lines +125 to +134
async function copyMarkdownToClipboard() {
const mdUrl = `https://elysiajs.com${router.route.path.replace(/.html$/g, '')}.md`
try {
const response = await fetch(mdUrl)
const markdown = await response.text()
await navigator.clipboard.writeText(markdown)
} catch (error) {
console.error('Failed to copy markdown:', error)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Hardcoded production URL breaks local development.

The function hardcodes https://elysiajs.com which will fail when developers run the site locally. During development, the fetch should resolve to the local dev server, not production.

Additionally, there's no user feedback—users won't know whether the copy succeeded or failed (only console logs).

🔧 Proposed fixes

Fix 1: Use relative URL to support both dev and production

 async function copyMarkdownToClipboard() {
-    const mdUrl = `https://elysiajs.com${router.route.path.replace(/.html$/g, '')}.md`
+    const mdUrl = `${router.route.path.replace(/\.html$/, '')}.md`
     try {
         const response = await fetch(mdUrl)
+        if (!response.ok) throw new Error(`Failed to fetch: ${response.status}`)
         const markdown = await response.text()
         await navigator.clipboard.writeText(markdown)
+        console.log('✓ Markdown copied to clipboard')
     } catch (error) {
         console.error('Failed to copy markdown:', error)
     }
 }

Fix 2: Add user feedback with timeout

 async function copyMarkdownToClipboard() {
-    const mdUrl = `https://elysiajs.com${router.route.path.replace(/.html$/g, '')}.md`
+    const mdUrl = `${router.route.path.replace(/\.html$/, '')}.md`
     try {
-        const response = await fetch(mdUrl)
+        const controller = new AbortController()
+        const timeoutId = setTimeout(() => controller.abort(), 10000)
+        const response = await fetch(mdUrl, { signal: controller.signal })
+        clearTimeout(timeoutId)
+        
+        if (!response.ok) throw new Error(`HTTP ${response.status}`)
         const markdown = await response.text()
         await navigator.clipboard.writeText(markdown)
+        
+        // TODO: Add toast notification for success
+        console.log('✓ Markdown copied to clipboard')
     } catch (error) {
         console.error('Failed to copy markdown:', error)
+        // TODO: Add toast notification for error
     }
 }

Notes:

  • Removed the unnecessary g flag from the regex (only one match at end of string)
  • Added response status check
  • Fix 2 includes abort controller for 10-second timeout
  • Consider adding visual feedback (toast/notification) instead of just console logs
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function copyMarkdownToClipboard() {
const mdUrl = `https://elysiajs.com${router.route.path.replace(/.html$/g, '')}.md`
try {
const response = await fetch(mdUrl)
const markdown = await response.text()
await navigator.clipboard.writeText(markdown)
} catch (error) {
console.error('Failed to copy markdown:', error)
}
}
async function copyMarkdownToClipboard() {
const mdUrl = `${router.route.path.replace(/\.html$/, '')}.md`
try {
const response = await fetch(mdUrl)
if (!response.ok) throw new Error(`Failed to fetch: ${response.status}`)
const markdown = await response.text()
await navigator.clipboard.writeText(markdown)
console.log('✓ Markdown copied to clipboard')
} catch (error) {
console.error('Failed to copy markdown:', error)
}
}
Suggested change
async function copyMarkdownToClipboard() {
const mdUrl = `https://elysiajs.com${router.route.path.replace(/.html$/g, '')}.md`
try {
const response = await fetch(mdUrl)
const markdown = await response.text()
await navigator.clipboard.writeText(markdown)
} catch (error) {
console.error('Failed to copy markdown:', error)
}
}
async function copyMarkdownToClipboard() {
const mdUrl = `${router.route.path.replace(/\.html$/, '')}.md`
try {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 10000)
const response = await fetch(mdUrl, { signal: controller.signal })
clearTimeout(timeoutId)
if (!response.ok) throw new Error(`HTTP ${response.status}`)
const markdown = await response.text()
await navigator.clipboard.writeText(markdown)
// TODO: Add toast notification for success
console.log('✓ Markdown copied to clipboard')
} catch (error) {
console.error('Failed to copy markdown:', error)
// TODO: Add toast notification for error
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant