GitHub や Zenn などでは当たり前のようにできるコードブロックのコピーですが、 Hugo 上ではデフォルトでできません。さすがに不便すぎるので作っていきましょう。 ついでに、ファイルパスを表示できるようにしましょう。
こんな感じです これを markdown 上で表現するには以下のように書きます。
```text {data-filename="ファイル名をつけられます"} こんな感じです ``` 変更・追加するファイルはそれぞれ以下になります。
コピーボタン追加 layout/partials/head.html static/css/code-copy.css static/js/code-copy.js ファイル名追加 layout/partials/head.html static/css/code-copy.css <link rel="stylesheet" href="/css/code-copy.css"> <link rel="stylesheet" href="/css/highlight.css"> .code-block { position: relative; } .copy-btn { position: absolute; top: 2px; right: 12px; padding: 4px 8px; font-size: 0.75rem; border-radius: 6px; background: #1e293b; color: #fff; border: none; cursor: pointer; opacity: 0.8; z-index: 10; } .copy-btn:hover { opacity: 1; } document.addEventListener("DOMContentLoaded", () => { const blocks = document.querySelectorAll("pre > code"); blocks.forEach((code) => { const pre = code.parentElement; // すでに処理済みならスキップ if (pre.parentElement.classList.contains("code-block")) return; const wrapper = document.createElement("div"); wrapper.className = "code-block"; // ファイル名要素の作成 const highlight = pre.closest(".highlight"); if (highlight && highlight.dataset.filename) { const filename = document.createElement("div"); filename.className = "code-filename"; filename.textContent = highlight.dataset.filename; wrapper.appendChild(filename); } const button = document.createElement("button"); button.className = "copy-btn"; button.textContent = "Copy"; button.addEventListener("click", async () => { await navigator.clipboard.writeText(code.textContent); button.textContent = "Copied!"; setTimeout(() => (button.textContent = "Copy"), 1500); }); pre.parentNode.insertBefore(wrapper, pre); wrapper.appendChild(button); wrapper.appendChild(pre); }); }); .highlight[data-filename] { position: relative; padding-top: 0; } .code-filename { position: relative; padding: 6px 12px; font-size: 0.75rem; font-family: monospace; background: #0f172a; color: #e5e7eb; border-bottom-right-radius: 8px; user-select: text; cursor: text; }