Skip to content
Open
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
54 changes: 45 additions & 9 deletions app/pages/package/[[org]]/[name].vue
Original file line number Diff line number Diff line change
Expand Up @@ -96,24 +96,60 @@ 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()
}
}

// Safari requires clipboard writes synchronously within a user gesture.
// Passing a Promise into ClipboardItem lets clipboard.write() stay
// synchronous while the fetch resolves asynchronously inside the item.
// See: https://wolfgangrittner.dev/how-to-use-clipboard-api-in-safari/
async function copyReadmeHandler() {
await fetchReadmeMarkdown()

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

try {
const item = new ClipboardItem({
'text/plain': (async () => {
await fetchReadmeMarkdown()
const markdown = readmeMarkdownData.value?.markdown
if (!markdown) throw new Error('No markdown')
return new Blob([markdown], { type: 'text/plain' })
})(),
})
await navigator.clipboard.write([item])
copied = true
} catch {
// Fallback for browsers without ClipboardItem Promise support
await fetchReadmeMarkdown()
const markdown = readmeMarkdownData.value?.markdown
if (markdown) {
try {
await navigator.clipboard.writeText(markdown)
copied = true
} catch {
// last resort: execCommand
const textarea = document.createElement('textarea')
textarea.value = markdown
textarea.style.position = 'fixed'
textarea.style.opacity = '0'
document.body.appendChild(textarea)
textarea.select()
copied = document.execCommand('copy')
document.body.removeChild(textarea)
}
}
}

await copyReadme(markdown)
if (copied) {
copiedReadme.value = true
setTimeout(() => {
copiedReadme.value = false
}, 2000)
}
}

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