Hugo页面代码块添加复制按钮

希望在有代码块的博客文章中的代码块中设置一个与其他博客平台类似的复制按钮,实现点击自动将代码内容复制到剪贴板的功能。主要参考Hugo 复制代码按钮

javascript 代码

[theme]/static/js/ 目录下新建 clipboard.js 文件,文件内容可以直接复制参考链接中的代码。

// buttons
const svgCopy =
  '<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true"><path fill-rule="evenodd" d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25v-7.5z"></path><path fill-rule="evenodd" d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0114.25 11h-7.5A1.75 1.75 0 015 9.25v-7.5zm1.75-.25a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25h-7.5z"></path></svg>';

const svgCheck =
  '<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true"><path fill-rule="evenodd" d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"></path></svg>';

// add button function
const addCopyButtons = (clipboard) => {
  // 1. Look for pre > code elements in the DOM
  document.querySelectorAll("pre > code").forEach((codeBlock) => {
    // 2. Create a button that will trigger a copy operation
    const button = document.createElement("button");
    button.className = "clipboard-button";
    button.type = "button";
    button.title = "Copy";
    button.innerHTML = svgCopy;
    button.addEventListener("click", () => {
      clipboard.writeText(codeBlock.innerText).then(
        () => {
          button.blur();
          button.innerHTML = svgCheck;
          setTimeout(() => (button.innerHTML = svgCopy), 2000);
        },
        (error) => (button.innerHTML = "Error")
      );
    });
    // 3. Append the button after the pre tag (.highlight > pre > button > code)
    const pre = codeBlock.parentNode;
    pre.parentNode.insertBefore(button, pre.nextSibling);
  });
};

// trigger function
if (navigator && navigator.clipboard) {
  addCopyButtons(navigator.clipboard);
} else {
  const script = document.createElement("script");
  script.src =
    "https://cdnjs.cloudflare.com/ajax/libs/clipboard-polyfill/3.0.3/promise/clipboard-polyfill.promise.min.js";
  script.integrity = "sha512-O9Q+AhI1w7LT1/tHysPWDwwrgB1fKJ/nXPNLC30i8LF6RdSz4dGZyWB9WySag3DZMdGuK5yHJEdKXMKI2m5uSQ==";
  script.crossOrigin = "anonymous";
  script.referrerpolicy = "no-referrer";
  script.onload = () => addCopyButtons(clipboard);
  document.body.appendChild(script);
}

javascript 引入

在 single.html 的页面元素中引入上面的 js 文件,具体可以在 single.html 中最后的区块中引用的 footer-mobile.html 中引入,即在 footer-mobile.html 的 footer 区块中加入下面的引用代码。

<!-- before code -->

<!-- copy code -->
{{ if (findRE "<code" .Content 1) }}
    <script src="{{"/js/clipboard.js" | relURL}}"></script>
{{ end }}

这里需要注意的是我的模板是在 noteworthy 模板的基础上修改的,其 singe.html 实际引用的是 footer-mobile.html 而不是 footer.html。因此应该在 footer-mobile.html 中添加上面的引用代码。

css 样式

我的模板的代码区块也是暗色主题的,可以直接借用参考链接中的样式,因此在 [theme]/assets/css/ 下新建 code-fense.css 文件,在里面添加参考链接中的样式。不过需要注意的是参考链接中的样式与 javascript 代码中的样式两者中对复制按钮的类名定义是不一样的,所以需要将样式中所有的 copy-code-button 替换为代码对应的 clipboard-button ,样式才能正常应用。

.highlight {
  position: relative;
}

.clipboard-button {
  color: var(--white);
  background-color: rgba(255,255,255,50%);
  border: none;
  border-radius: 6px;
  padding: 0 5px 5px 5px;
  font-size: 1rem;
  position: absolute;
  z-index: 1;
  right: 0;
  top: 0;
  margin: 10px;
  transition: .1s;
  opacity: 0.5;
}

.clipboard-button > svg {
  fill: var(--white);
}

.clipboard-button:hover,
.clipboard-button:focus,
pre:active ~ .clipboard-button,
pre:focus ~ .clipboard-button,
div.highlight:active > .clipboard-button,
div.highlight:focus > .clipboard-button {
  cursor: pointer;
  opacity: 1;
}

css 引入

自定义样式的应用还同时参考了同一作者的如何在 Hugo 中添加自定义 CSS

我的选择是在 single.html 中的稍前位置加入引用代码。

{{ if .Site.Params.customCSS }}

{{ $style := resources.Match "css/code-fense.css" | resources.Concat "custom.css" | minify | fingerprint }}

通过上述方式引入后,在 config.toml 中加入下面的设置就大功告成了。

[params]
    # other setting
    customCSS=true

参考链接

Hugo 复制代码按钮

如何在 Hugo 中添加自定义 CSS

Hugo: Add Copy-to-Clipboard Button to Code Blocks with Vanilla JS