Skip to content
Closed
Changes from 3 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
40 changes: 35 additions & 5 deletions app/pages/package/[[org]]/[name].vue
Original file line number Diff line number Diff line change
Expand Up @@ -96,24 +96,54 @@ const {
)

//copy README file as Markdown
const { copied: copiedReadme, copy: copyReadme } = useClipboard({
source: () => '',
copiedDuring: 2000,
})
const copiedReadme = shallowRef(false)

function prefetchReadmeMarkdown() {
if (readmeMarkdownStatus.value === 'idle') {
fetchReadmeMarkdown()
}
}

// Fallback for Safari: navigator.clipboard.writeText() must be called
// synchronously within a user gesture. The async fetch breaks that chain,
// so we fall back to execCommand('copy') via a temporary textarea.
function copyViaExecCommand(text: string): boolean {
const textarea = document.createElement('textarea')
textarea.value = text
textarea.style.position = 'fixed'
textarea.style.opacity = '0'
document.body.appendChild(textarea)
textarea.select()
try {
return document.execCommand('copy')
} finally {
document.body.removeChild(textarea)
}
}

async function copyReadmeHandler() {
await fetchReadmeMarkdown()

const markdown = readmeMarkdownData.value?.markdown
if (!markdown) return

await copyReadme(markdown)
// Try the modern clipboard API first, then fall back to execCommand.
// Safari requires clipboard writes synchronously within a user gesture β€”
// the async fetch above breaks that chain, so writeText() will reject.
let success = false
try {
await navigator.clipboard.writeText(markdown)
success = true
} catch {
success = copyViaExecCommand(markdown)
}

if (success) {
copiedReadme.value = true
setTimeout(() => {
copiedReadme.value = false
}, 2000)
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
}

// Track active TOC item based on scroll position
Expand Down
Loading