website/src/components/CopyText.astro
2026-09-08 19:29:17 -04:00

53 lines
1.4 KiB
Plaintext

---
interface Props {
value: string;
display?: string;
label?: string;
event?: string;
}
const { value, display = value, label = `copy ${value}`, event } = Astro.props;
---
<button
class="copy"
type="button"
data-copy={value}
aria-label={label}
data-umami-event={event}
>
<span class="copy__text">{display}</span>
<svg class="copy__icon" viewBox="0 0 24 24" aria-hidden="true">
<rect x="9" y="9" width="11" height="11" rx="2"></rect>
<path d="M5 15V5a2 2 0 0 1 2-2h10"></path>
</svg>
<svg class="copy__check" viewBox="0 0 24 24" aria-hidden="true">
<path d="M20 6 9 17l-5-5"></path>
</svg>
<span class="tip" aria-hidden="true">copied</span>
</button>
<script>
document.querySelectorAll<HTMLButtonElement>("[data-copy]").forEach((btn) => {
if (btn.dataset.copyBound) return;
btn.dataset.copyBound = "1";
btn.addEventListener("click", async () => {
const val = btn.dataset.copy ?? "";
try {
await navigator.clipboard.writeText(val);
} catch {
const t = btn.querySelector(".copy__text");
if (t) {
const r = document.createRange();
r.selectNodeContents(t);
const sel = getSelection();
sel?.removeAllRanges();
sel?.addRange(r);
document.execCommand?.("copy");
}
}
btn.classList.add("copied");
setTimeout(() => btn.classList.remove("copied"), 1600);
});
});
</script>