前回の記事で、Cocoon のコードブロックにコピーボタンを追加してみたものの、表示がやっぱり質素で、もう少しかっこいい表示にしたい。
前回の記事:
そこで、フリーの SVG アイコン素材を用いて、コピーボタンとなるように修正してみた。
完成後の表示イメージ:

大筋のコードは前回と概ね同じで、ボタンの部分を SVG 画像に差し替え。
push down でエフェクトが付くように、mousedown, mouseup, mouseleave に addEventListener を追加した。
JavaScript:
document.addEventListener("DOMContentLoaded", () => {
svgImage = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="24" height="24">
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
<path d="M464 0H144c-26.5 0-48 21.5-48 48v48H48c-26.5 0-48 21.5-48 48v320c0 26.5 21.5 48 48 48h320c26.5 0 48-21.5 48-48v-48h48c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zM362 464H54a6 6 0 0 1 -6-6V150a6 6 0 0 1 6-6h42v224c0 26.5 21.5 48 48 48h224v42a6 6 0 0 1 -6 6zm96-96H150a6 6 0 0 1 -6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v308a6 6 0 0 1 -6 6z"/>
</svg>`;
function createSvgElement(htmlText) {
element = new DOMParser().parseFromString(htmlText, "text/html").body.firstElementChild;
element.style.fill = "rgb(200, 200, 200)";
element.style.opacity = "0.8";
return element;
}
svgElement = createSvgElement(svgImage);
// Get all <pre> elements
const preElements = document.querySelectorAll("pre");
preElements.forEach(pre => {
const code = pre.querySelector("code");
if (code) {
// Create a copy button
const copyButton = document.createElement("button");
copyButton.style.position = "absolute";
copyButton.style.top = "5px";
copyButton.style.right = "5px";
copyButton.style.width = "35px";
copyButton.style.height = "35px";
copyButton.style.border = "none";
copyButton.style.background = "transparent";
copyButton.style.cursor = "pointer";
// Add SVG icon
copyButton.appendChild(svgElement.cloneNode(true));
// Add tooltip
copyButton.title = "Copy to clipboard";
// Add push effect
copyButton.addEventListener("mousedown", () => {
copyButton.style.transform = "translateY(2px)";
});
copyButton.addEventListener("mouseup", () => {
copyButton.style.transform = "translateY(0)";
});
copyButton.addEventListener("mouseleave", () => {
copyButton.style.transform = "translateY(0)";
});
// Add click action
copyButton.addEventListener("click", () => {
const codeText = code.textContent;
navigator.clipboard.writeText(codeText).then(() => {
// Show copied message
const copiedMessage = document.createElement("div");
copiedMessage.textContent = "Copied!";
copiedMessage.style.position = "absolute";
copiedMessage.style.top = "-30px";
copiedMessage.style.right = "5px";
copiedMessage.style.backgroundColor = "black";
copiedMessage.style.color = "white";
copiedMessage.style.padding = "5px 10px";
copiedMessage.style.borderRadius = "3px";
copiedMessage.style.fontSize = "12px";
copiedMessage.style.zIndex = "10";
copiedMessage.style.opacity = "1";
copiedMessage.style.transition = "opacity 0.5s";
pre.parentNode.appendChild(copiedMessage);
setTimeout(() => {
copiedMessage.style.opacity = "0";
copiedMessage.addEventListener("transitionend", () => {
copiedMessage.remove();
});
}, 1500);
}).catch(err => {
console.error("Failed to copy", err);
});
});
// To maintain the position of the copy button, wrap the <pre> element in a div element
const container = document.createElement("div");
container.style.position = "relative";
container.style.width = "100%";
pre.parentNode.insertBefore(container, pre);
container.appendChild(pre);
container.appendChild(copyButton);
}
});
});
JavaScript は、「外観」→「テーマファイルエディター」→「javascript.js」から追加

コピーボタンのデザインは、Zenn を参考にさせていただきました。
https://zenn.dev/