From 3f87d78b33d756a936ec654cf5646599320b20df Mon Sep 17 00:00:00 2001 From: David Lapshin Date: Thu, 9 May 2024 22:01:25 +0300 Subject: [PATCH] Add optional copy code button! --- config.toml | 6 +++- sass/_main.scss | 55 ++++++++++++++++++++++++++++++++++++ static/copy-button.js | 31 ++++++++++++++++++++ templates/partials/head.html | 4 +++ 4 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 static/copy-button.js diff --git a/config.toml b/config.toml index 7f447a4..7f6c53a 100644 --- a/config.toml +++ b/config.toml @@ -48,6 +48,10 @@ source_url = "https://codeberg.org/daudix/duckquill" # "YOUR_STYLE.css", # "ALSO_YOUR_STYLE.css" # ] +# Whether to display "copy code" button on all code blocks +# that have the language set. +# See https://www.getzola.org/documentation/content/syntax-highlighting/ +show_copy_button = true [extra.nav] # Whether to show Atom/RSS feed button in the nav @@ -88,7 +92,7 @@ show_johnvert = false # Whether to show "Powered by Zola and Duckquill" show_powered_by = true # Whether to show link to website source -show_source = true +show_source = false # Based on https://carlschwan.eu/2020/12/29/adding-comments-to-your-static-blog-with-mastodon/ # diff --git a/sass/_main.scss b/sass/_main.scss index 823901f..274af40 100644 --- a/sass/_main.scss +++ b/sass/_main.scss @@ -193,6 +193,61 @@ pre { overflow: auto; line-height: normal; // Unset line height + &[class*="language-"] { + position: relative; + + & button { + all: unset; + display: inline-flex; + position: absolute; + top: 0.5rem; + right: 0.5rem; + transition: var(--transition); + border-radius: 50%; + background-color: var(--fg-muted-1); + padding: 0.5rem; + width: 1rem; + height: 1rem; + cursor: pointer; + + &:hover { + background-color: var(--fg-muted-2); + + i { + background-color: var(--fg-muted-5); + } + } + + &:active { + transform: scale(var(--active)); + } + + &.active { + background-color: var(--primary-color-alpha); + + i { + background-color: var(--primary-color); + mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E%3Cpath d='M7.883 0q-.486.008-.965.074a7.98 7.98 0 0 0-4.602 2.293 8.01 8.01 0 0 0-1.23 9.664 8.015 8.015 0 0 0 9.02 3.684 8 8 0 0 0 5.89-7.75 1 1 0 1 0-2 .008 5.986 5.986 0 0 1-4.418 5.816 5.996 5.996 0 0 1-6.762-2.766 5.99 5.99 0 0 1 .922-7.25 5.99 5.99 0 0 1 7.239-.984 1 1 0 0 0 1.363-.371c.273-.48.11-1.09-.371-1.367A8 8 0 0 0 9.492.14 8 8 0 0 0 7.882 0m7.15 1.998-.1.002a1 1 0 0 0-.687.34L7.95 9.535 5.707 7.29A1 1 0 0 0 4 8a1 1 0 0 0 .293.707l3 3c.195.195.465.3.742.293.277-.012.535-.133.719-.344l7-8A1 1 0 0 0 16 2.934a1 1 0 0 0-.34-.688 1 1 0 0 0-.627-.248'/%3E%3C/svg%3E"); + -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E%3Cpath d='M7.883 0q-.486.008-.965.074a7.98 7.98 0 0 0-4.602 2.293 8.01 8.01 0 0 0-1.23 9.664 8.015 8.015 0 0 0 9.02 3.684 8 8 0 0 0 5.89-7.75 1 1 0 1 0-2 .008 5.986 5.986 0 0 1-4.418 5.816 5.996 5.996 0 0 1-6.762-2.766 5.99 5.99 0 0 1 .922-7.25 5.99 5.99 0 0 1 7.239-.984 1 1 0 0 0 1.363-.371c.273-.48.11-1.09-.371-1.367A8 8 0 0 0 9.492.14 8 8 0 0 0 7.882 0m7.15 1.998-.1.002a1 1 0 0 0-.687.34L7.95 9.535 5.707 7.29A1 1 0 0 0 4 8a1 1 0 0 0 .293.707l3 3c.195.195.465.3.742.293.277-.012.535-.133.719-.344l7-8A1 1 0 0 0 16 2.934a1 1 0 0 0-.34-.688 1 1 0 0 0-.627-.248'/%3E%3C/svg%3E"); + } + } + + i { + -webkit-mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' height='16' width='16' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 3c0-1.645 1.355-3 3-3h5c1.645 0 3 1.355 3 3 0 .55-.45 1-1 1s-1-.45-1-1c0-.57-.43-1-1-1H3c-.57 0-1 .43-1 1v5c0 .57.43 1 1 1 .55 0 1 .45 1 1s-.45 1-1 1c-1.645 0-3-1.355-3-3zm5 5c0-1.645 1.355-3 3-3h5c1.645 0 3 1.355 3 3v5c0 1.645-1.355 3-3 3H8c-1.645 0-3-1.355-3-3zm2 0v5c0 .57.43 1 1 1h5c.57 0 1-.43 1-1V8c0-.57-.43-1-1-1H8c-.57 0-1 .43-1 1m0 0'/%3E%3C/svg%3E"); + display: inline-block; + mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' height='16' width='16' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 3c0-1.645 1.355-3 3-3h5c1.645 0 3 1.355 3 3 0 .55-.45 1-1 1s-1-.45-1-1c0-.57-.43-1-1-1H3c-.57 0-1 .43-1 1v5c0 .57.43 1 1 1 .55 0 1 .45 1 1s-.45 1-1 1c-1.645 0-3-1.355-3-3zm5 5c0-1.645 1.355-3 3-3h5c1.645 0 3 1.355 3 3v5c0 1.645-1.355 3-3 3H8c-1.645 0-3-1.355-3-3zm2 0v5c0 .57.43 1 1 1h5c.57 0 1-.43 1-1V8c0-.57-.43-1-1-1H8c-.57 0-1 .43-1 1m0 0'/%3E%3C/svg%3E"); + transition: var(--transition); + background-color: var(--fg-muted-4); + width: 1rem; + height: 1rem; + font-style: normal; + font-variant: normal; + line-height: 1; + text-rendering: auto; + } + } + } + table td { border: none; padding: 0; diff --git a/static/copy-button.js b/static/copy-button.js new file mode 100644 index 0000000..deda191 --- /dev/null +++ b/static/copy-button.js @@ -0,0 +1,31 @@ +// Based on https://www.roboleary.net/2022/01/13/copy-code-to-clipboard-blog.html +document.addEventListener("DOMContentLoaded", function () { + let blocks = document.querySelectorAll("pre[class^='language-']"); + + blocks.forEach((block) => { + if (navigator.clipboard) { + let button = document.createElement("button"); + let icon = document.createElement("i"); + + button.appendChild(icon); + block.appendChild(button); + + button.addEventListener("click", async () => { + await copyCode(block, button); + }); + } + }); + + async function copyCode(block, button) { + let code = block.querySelector("code"); + let text = code.innerText; + + await navigator.clipboard.writeText(text); + + button.classList.add("active"); + + setTimeout(() => { + button.classList.remove("active"); + }, 800); + } +}); diff --git a/templates/partials/head.html b/templates/partials/head.html index 3d60f02..aa06c38 100644 --- a/templates/partials/head.html +++ b/templates/partials/head.html @@ -33,6 +33,10 @@ } + {% if config.extra.show_copy_button %} + + {% endif %} + {% if config.extra.comments %} {% endif %}