feat: copy button for code blocks (#67)

* Add  code copy

* fix: safari copyButton style

* fix: addPreCopyButton up time

* modify: CopyButton style

* fix: Duplicate rendering issue with copy button
This commit is contained in:
Kuroki_Tsuki 2024-06-21 19:58:47 +08:00 committed by saicaca
parent 815692899d
commit 88a7414625
6 changed files with 67 additions and 0 deletions

View File

@ -13,6 +13,58 @@ const className = Astro.props.class;
<slot/> <slot/>
</div> </div>
<script>
import { i18n } from "@i18n/translation";
import I18nKey from "@i18n/i18nKey";
const observer = new MutationObserver(addPreCopyButton);
observer.observe(document.body, { childList: true, subtree: true });
document.addEventListener("DOMContentLoaded", addPreCopyButton);
function addPreCopyButton() {
observer.disconnect();
let codeBlocks = Array.from(document.querySelectorAll("pre"));
for (let codeBlock of codeBlocks) {
if (codeBlock.parentElement?.nodeName === "DIV" && codeBlock.parentElement?.classList.contains("code-block")) continue
let wrapper = document.createElement("div");
wrapper.className = "relative code-block";
let copyButton = document.createElement("button");
copyButton.className = "copy-code btn-regular absolute top-0 right-0 text-sm px-3 py-2 rounded-bl-lg rounded-tr-lg opacity-75 hover:opacity-100 transition-all duration-200 ease-in-out";
copyButton.textContent = i18n(I18nKey.codeCopy);
codeBlock.setAttribute("tabindex", "0");
if (codeBlock.parentNode) {
codeBlock.parentNode.insertBefore(wrapper, codeBlock);
}
wrapper.appendChild(codeBlock);
wrapper.appendChild(copyButton);
copyButton.addEventListener("click", async () => {
let text = codeBlock?.querySelector("code")?.innerText;
await navigator.clipboard.writeText(text);
copyButton.textContent = i18n(I18nKey.codeCopied);
copyButton.classList.toggle("opacity-100");
setTimeout(() => {
copyButton.textContent = i18n(I18nKey.codeCopy);
copyButton.classList.toggle("opacity-100");
}, 700);
});
}
observer.observe(document.body, { childList: true, subtree: true });
}
</script>
<style lang="stylus" is:global> <style lang="stylus" is:global>
.custom-md .custom-md
h1, h2, h3, h4, h5, h6 h1, h2, h3, h4, h5, h6

View File

@ -32,6 +32,9 @@ enum I18nKey {
author = 'author', author = 'author',
publishedAt = 'publishedAt', publishedAt = 'publishedAt',
license = 'license', license = 'license',
codeCopy = 'copy',
codeCopied = 'codeCopied',
} }
export default I18nKey export default I18nKey

View File

@ -35,4 +35,7 @@ export const en: Translation = {
[Key.author]: 'Author', [Key.author]: 'Author',
[Key.publishedAt]: 'Published at', [Key.publishedAt]: 'Published at',
[Key.license]: 'License', [Key.license]: 'License',
[Key.codeCopy]: 'Copy',
[Key.codeCopied]: 'Code copied',
} }

View File

@ -35,4 +35,7 @@ export const ja: Translation = {
[Key.author]: '作者', [Key.author]: '作者',
[Key.publishedAt]: '公開日', [Key.publishedAt]: '公開日',
[Key.license]: 'ライセンス', [Key.license]: 'ライセンス',
[Key.codeCopy]: 'コピー',
[Key.codeCopied]: 'コピーしました',
} }

View File

@ -35,4 +35,7 @@ export const zh_CN: Translation = {
[Key.author]: '作者', [Key.author]: '作者',
[Key.publishedAt]: '发布于', [Key.publishedAt]: '发布于',
[Key.license]: '许可协议', [Key.license]: '许可协议',
[Key.codeCopy]: '复制',
[Key.codeCopied]: '复制成功',
} }

View File

@ -35,4 +35,7 @@ export const zh_TW: Translation = {
[Key.author]: '作者', [Key.author]: '作者',
[Key.publishedAt]: '發佈於', [Key.publishedAt]: '發佈於',
[Key.license]: '許可協議', [Key.license]: '許可協議',
[Key.codeCopy]: '複製',
[Key.codeCopied]: '複製成功',
} }