chore: add code copy button icons in js (#133)

This commit is contained in:
Xin 2023-10-07 20:01:19 +01:00 committed by GitHub
parent 5f4c7423d0
commit 28a20e1e7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 32 deletions

View File

@ -1,30 +1,63 @@
document.querySelectorAll('.code-copy-btn').forEach(function (button) { // Copy button for code blocks
button.addEventListener('click', function (e) {
e.preventDefault(); document.addEventListener('DOMContentLoaded', function () {
const targetId = button.getAttribute('data-clipboard-target'); const getCopyIcon = () => {
const target = document.querySelector(targetId); const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
let codeElement; svg.innerHTML = `
if (target.tagName === 'CODE') { <path stroke-linecap="round" stroke-linejoin="round" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
codeElement = target; `;
} else { svg.setAttribute('fill', 'none');
// Select the last code element in case line numbers are present svg.setAttribute('viewBox', '0 0 24 24');
const codeElements = target.querySelectorAll('code'); svg.setAttribute('stroke', 'currentColor');
codeElement = codeElements[codeElements.length - 1]; svg.setAttribute('stroke-width', '2');
} return svg;
if (codeElement) { }
// Replace double newlines with single newlines in the innerText
// as each line inside <span> has trailing newline '\n' const getSuccessIcon = () => {
const code = codeElement.innerText.replace(/\n\n/g, '\n'); const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
navigator.clipboard.writeText(code).then(function () { svg.innerHTML = `
button.classList.add('copied'); <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
setTimeout(function () { `;
button.classList.remove('copied'); svg.setAttribute('fill', 'none');
}, 500); svg.setAttribute('viewBox', '0 0 24 24');
}).catch(function (err) { svg.setAttribute('stroke', 'currentColor');
console.error('Failed to copy text: ', err); svg.setAttribute('stroke-width', '2');
}); return svg;
} else { }
console.error('Target element not found');
} document.querySelectorAll('.code-copy-btn').forEach(function (button) {
// Add copy and success icons
button.querySelector('.copy-icon')?.appendChild(getCopyIcon());
button.querySelector('.success-icon')?.appendChild(getSuccessIcon());
// Add click event listener for copy button
button.addEventListener('click', function (e) {
e.preventDefault();
const targetId = button.getAttribute('data-clipboard-target');
const target = document.querySelector(targetId);
let codeElement;
if (target.tagName === 'CODE') {
codeElement = target;
} else {
// Select the last code element in case line numbers are present
const codeElements = target.querySelectorAll('code');
codeElement = codeElements[codeElements.length - 1];
}
if (codeElement) {
// Replace double newlines with single newlines in the innerText
// as each line inside <span> has trailing newline '\n'
const code = codeElement.innerText.replace(/\n\n/g, '\n');
navigator.clipboard.writeText(code).then(function () {
button.classList.add('copied');
setTimeout(function () {
button.classList.remove('copied');
}, 500);
}).catch(function (err) {
console.error('Failed to copy text: ', err);
});
} else {
console.error('Target element not found');
}
});
}); });
}); });

View File

@ -154,6 +154,7 @@
"contrast-more:text-gray-800", "contrast-more:text-gray-800",
"contrast-more:text-gray-900", "contrast-more:text-gray-900",
"contrast-more:underline", "contrast-more:underline",
"copy-icon",
"cursor-default", "cursor-default",
"cursor-pointer", "cursor-pointer",
"dark:before:bg-neutral-800", "dark:before:bg-neutral-800",
@ -590,4 +591,4 @@
], ],
"ids": null "ids": null
} }
} }

View File

@ -15,9 +15,13 @@
<pre><code id="code-block-{{ .Ordinal }}">{{ .Inner }}</code></pre> <pre><code id="code-block-{{ .Ordinal }}">{{ .Inner }}</code></pre>
{{- end -}} {{- end -}}
<div class="opacity-0 transition group-hover/code:opacity-100 flex gap-1 absolute m-[11px] right-0 {{ if $filename }}top-8{{ else }}top-0{{ end }}"> <div class="opacity-0 transition group-hover/code:opacity-100 flex gap-1 absolute m-[11px] right-0 {{ if $filename }}top-8{{ else }}top-0{{ end }}">
<button class="code-copy-btn group/copybtn transition-all active:opacity-50 bg-primary-700/5 border border-black/5 text-gray-600 hover:text-gray-900 rounded-md p-1.5 dark:bg-primary-300/10 dark:border-white/10 dark:text-gray-400 dark:hover:text-gray-50" title="Copy code" data-clipboard-target="#code-block-{{ .Ordinal }}"> <button
{{ partial "utils/icon.html" (dict "name" "copy" "attributes" "class=\"group-[.copied]/copybtn:hidden pointer-events-none h-4 w-4\"") }} class="code-copy-btn group/copybtn transition-all active:opacity-50 bg-primary-700/5 border border-black/5 text-gray-600 hover:text-gray-900 rounded-md p-1.5 dark:bg-primary-300/10 dark:border-white/10 dark:text-gray-400 dark:hover:text-gray-50"
{{ partial "utils/icon.html" (dict "name" "check" "attributes" "class=\"hidden group-[.copied]/copybtn:block success-icon pointer-events-none h-4 w-4\"") }} title="Copy code"
data-clipboard-target="#code-block-{{ .Ordinal }}"
>
<div class="group-[.copied]/copybtn:hidden copy-icon pointer-events-none h-4 w-4"></div>
<div class="hidden group-[.copied]/copybtn:block success-icon pointer-events-none h-4 w-4"></div>
</button> </button>
</div> </div>
</div> </div>