blog/src/components/Widgets/CodeCopyButton.astro
2025-05-27 14:56:15 +01:00

77 lines
2.1 KiB
Text

<script>
const copyIcons = {
copy:
`<svg
viewBox="0 0 24 24"
fill="currentColor"
>
<path d="M6.9.8v18h14.5V.8zm12.8 16h-11v-14h11z"/>
<path d="M4.3 21.2V5.6l-1.7.5v17.1h14.3l.6-2z"/>
</svg>`,
success:
`<svg
viewBox="0 0 24 24"
fill="currentColor"
>
<path d="m23.1 6.4-1.3-1.3L9.4 16.6l-6.3-5.4-1.2 1.2L9.4 20z"/>
</svg>`,
}
// Track timeout references for each button to manage icon state transitions
const activeTimeouts = new WeakMap<HTMLButtonElement, ReturnType<typeof setTimeout>>()
async function handleCopy(button: HTMLButtonElement) {
const codeElement = button.parentElement?.querySelector('pre code')
const code = codeElement?.textContent || ''
try {
await navigator.clipboard.writeText(code)
// Clear existing timeout to prevent icon state conflicts on multiple clicks
const existingTimeout = activeTimeouts.get(button)
if (existingTimeout) {
clearTimeout(existingTimeout)
}
button.innerHTML = copyIcons.success
button.classList.add('copy-success')
// Set timeout to revert to copy icon after 1.5s
const timeoutId = setTimeout(() => {
button.innerHTML = copyIcons.copy
button.classList.remove('copy-success')
activeTimeouts.delete(button)
}, 1500)
activeTimeouts.set(button, timeoutId)
}
catch {
}
}
// Initialize copy buttons with icons and mark them to prevent duplicate initialization
function setupCodeCopyButtons() {
document
.querySelectorAll<HTMLButtonElement>('.code-copy-button:not([data-initialized])')
.forEach((button) => {
button.innerHTML = copyIcons.copy
button.setAttribute('data-initialized', 'true')
})
}
// Use event delegation for better performance
document.addEventListener('click', (e) => {
if (!(e.target instanceof HTMLElement))
return
// Find closest button element if clicked on button or child element
const button = e.target.closest('.code-copy-button') as HTMLButtonElement | null
if (button) {
handleCopy(button)
}
}, { passive: true })
setupCodeCopyButtons()
document.addEventListener('astro:page-load', setupCodeCopyButtons)
</script>