feat: add button to copy code blocks (#228)

BREAKING CHANGE: The `--code-max-height` formatting is applied only to code blocks that use syntax highlighting, see [documentation](https://geekdocs.de/features/code-blocks/).
This commit is contained in:
Robert Kaussow 2021-11-07 22:12:14 +01:00 committed by GitHub
parent d1267ac587
commit 75f56d8fad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 138 additions and 7 deletions

View file

@ -2,7 +2,7 @@
title: Code Blocks title: Code Blocks
--- ---
There are multiple ways to add code blocks. Most of them works out of the box only the Hugo shortcode `<highlight>` need some configuration to work properly. There are several ways to add code blocks. Most of them work out of the box, only the Hugo short code `<highlight>` needs to be configured to work properly. The theme also provides some additional features like a copy button and an option to set the maximum length of code blocks. Both of these functions and the dependent formatting rely on the `.highlight` CSS class. You must ensure that you always assign a language to your code blocks if you want to use these functions. If you do not want to apply syntax highlighting, you can also specify `plain` or `text` as the language.
{{< toc >}} {{< toc >}}
@ -21,14 +21,14 @@ To display an inline shortcode use single quotes:
Code blocks can be uses without language specification: Code blocks can be uses without language specification:
````markdown ````markdown
``` ```Plain
some code some code
``` ```
```` ````
**Example:** **Example:**
```plain ```Plain
some code some code
``` ```

View file

@ -23,6 +23,10 @@
--code-accent-color: #e3e7eb; --code-accent-color: #e3e7eb;
--code-accent-color-lite: #eff1f3; --code-accent-color-lite: #eff1f3;
--code-copy-font-color: #6b7784;
--code-copy-border-color: #adb4bc;
--code-copy-success-color: #00c853;
--accent-color: #e9ecef; --accent-color: #e9ecef;
--accent-color-lite: #f8f9fa; --accent-color-lite: #f8f9fa;
@ -51,6 +55,10 @@
--code-accent-color: #e3e7eb; --code-accent-color: #e3e7eb;
--code-accent-color-lite: #eff1f3; --code-accent-color-lite: #eff1f3;
--code-copy-font-color: #6b7784;
--code-copy-border-color: #adb4bc;
--code-copy-success-color: #00c853;
--accent-color: #e9ecef; --accent-color: #e9ecef;
--accent-color-lite: #f8f9fa; --accent-color-lite: #f8f9fa;
@ -81,6 +89,10 @@
--code-accent-color: #262b2f; --code-accent-color: #262b2f;
--code-accent-color-lite: #2b3035; --code-accent-color-lite: #2b3035;
--code-copy-font-color: #adb4bc;
--code-copy-border-color: #808c98;
--code-copy-success-color: #00c853;
--accent-color: #2b3035; --accent-color: #2b3035;
--accent-color-lite: #2f353a; --accent-color-lite: #2f353a;
@ -109,6 +121,10 @@
--code-accent-color: #262b2f; --code-accent-color: #262b2f;
--code-accent-color-lite: #2b3035; --code-accent-color-lite: #2b3035;
--code-copy-font-color: #adb4bc;
--code-copy-border-color: #808c98;
--code-copy-success-color: #00c853;
--accent-color: #2b3035; --accent-color: #2b3035;
--accent-color-lite: #2f353a; --accent-color-lite: #2f353a;

View file

@ -10,3 +10,5 @@
<script defer src="{{ index .Site.Data.assets "js/clipboard.min.js" | relURL }}"></script> <script defer src="{{ index .Site.Data.assets "js/clipboard.min.js" | relURL }}"></script>
<script defer src="{{ index .Site.Data.assets "js/clipboard-loader.min.js" | relURL }}"></script> <script defer src="{{ index .Site.Data.assets "js/clipboard-loader.min.js" | relURL }}"></script>
{{ end }} {{ end }}
<script defer src="{{ index .Site.Data.assets "js/copycode.min.js" | relURL }}"></script>

5
src/icons/check.svg Normal file
View file

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 28 28">
<title>check</title>
<path d="M8.885 20.197l16.874-16.874 2.24 2.24-19.114 19.114-8.885-8.885 2.24-2.24z"></path>
</svg>

After

Width:  |  Height:  |  Size: 252 B

5
src/icons/copy.svg Normal file
View file

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 28 28">
<title>copy</title>
<path d="M23.502 25.438v-17.812h-13.94v17.812h13.94zM23.502 5.123q1.013 0 1.787 0.745t0.774 1.757v17.812q0 1.013-0.774 1.787t-1.787 0.774h-13.94q-1.013 0-1.787-0.774t-0.774-1.787v-17.812q0-1.013 0.774-1.757t1.787-0.745h13.94zM19.689 0v2.562h-15.251v17.812h-2.502v-17.812q0-1.013 0.745-1.787t1.757-0.774h15.251z"></path>
</svg>

After

Width:  |  Height:  |  Size: 478 B

View file

@ -1,3 +1,21 @@
document.addEventListener("DOMContentLoaded", function (event) { document.addEventListener("DOMContentLoaded", function (event) {
var clipboard = new ClipboardJS(".clip"); var clipboard = new ClipboardJS(".clip");
clipboard.on("success", function (e) {
const trigger = e.trigger;
if (trigger.hasAttribute("data-copy-feedback")) {
trigger.classList.add("gdoc-post__codecopy--success");
trigger.querySelector(".icon.copy").classList.add("hidden");
trigger.querySelector(".icon.check").classList.remove("hidden");
setTimeout(function () {
trigger.classList.remove("gdoc-post__codecopy--success");
trigger.querySelector(".icon.copy").classList.remove("hidden");
trigger.querySelector(".icon.check").classList.add("hidden");
}, 3000);
}
e.clearSelection();
});
}); });

34
src/js/copycode.js Normal file
View file

@ -0,0 +1,34 @@
function createCopyButton(highlightDiv) {
const button = document.createElement("span");
if (highlightDiv.querySelector(".lntable")) {
selector = ".lntable .lntd:last-child pre > code";
} else {
selector = "pre > code";
}
const codeToCopy = highlightDiv.querySelector(selector).innerText.trim();
button.classList.add(
"flex",
"align-center",
"justify-center",
"clip",
"gdoc-post__codecopy"
);
button.type = "button";
button.innerHTML =
'<svg class="icon copy"><use xlink:href="#gdoc_copy"></use></svg>' +
'<svg class="icon check hidden"><use xlink:href="#gdoc_check"></use></svg>';
button.setAttribute("data-clipboard-text", codeToCopy);
button.setAttribute("data-copy-feedback", "Copied!");
button.setAttribute("role", "button");
button.setAttribute("aria-label", "Copy");
highlightDiv.classList.add("gdoc-post__codecontainer");
highlightDiv.insertBefore(button, highlightDiv.firstChild);
}
document
.querySelectorAll(".highlight")
.forEach((highlightDiv) => createCopyButton(highlightDiv));

View file

@ -488,6 +488,45 @@ img {
font-size: $font-size-20; font-size: $font-size-20;
} }
} }
&__codecontainer {
position: relative;
&:hover > .gdoc-post__codecopy {
visibility: visible;
}
}
&__codecopy {
visibility: hidden;
position: absolute;
top: 0.5rem;
right: 0.5rem;
border: $border-2 solid var(--code-copy-border-color);
border-radius: $border-radius;
width: 2.2rem;
height: 2.2rem;
.icon {
top: 0;
width: $font-size-20;
height: $font-size-20;
color: var(--code-copy-font-color);
}
&:hover {
cursor: pointer;
}
&--success {
border-color: var(--code-copy-success-color);
.icon {
color: var(--code-copy-success-color);
}
}
}
} }
.gdoc-footer { .gdoc-footer {

View file

@ -35,6 +35,9 @@
} }
.highlight { .highlight {
overflow: auto;
max-height: var(--code-max-height);
pre.chroma { pre.chroma {
margin: 0; margin: 0;
} }

View file

@ -18,6 +18,10 @@
--code-accent-color-lite: #{darken($code-background, 2)}; --code-accent-color-lite: #{darken($code-background, 2)};
--code-font-color: #{$code-font-color}; --code-font-color: #{$code-font-color};
--code-copy-font-color: #{lighten($body-font-color, 24)};
--code-copy-border-color: #{lighten($body-font-color, 48)};
--code-copy-success-color: #{map.get($hint-colors, "ok")};
--accent-color: #{$gray-200}; --accent-color: #{$gray-200};
--accent-color-lite: #{$gray-100}; --accent-color-lite: #{$gray-100};
@ -61,6 +65,10 @@
--code-accent-color-lite: #{darken($code-background-dark, 2)}; --code-accent-color-lite: #{darken($code-background-dark, 2)};
--code-font-color: #{$code-font-color-dark}; --code-font-color: #{$code-font-color-dark};
--code-copy-font-color: #{lighten($body-font-color, 48)};
--code-copy-border-color: #{lighten($body-font-color, 32)};
--code-copy-success-color: #{map.get($hint-colors, "ok")};
--accent-color: #{darken($body-background-dark, 4)}; --accent-color: #{darken($body-background-dark, 4)};
--accent-color-lite: #{darken($body-background-dark, 2)}; --accent-color-lite: #{darken($body-background-dark, 2)};
@ -78,7 +86,8 @@
} }
.gdoc-markdown { .gdoc-markdown {
.gdoc-hint { .gdoc-hint,
.gdoc-post__codecopy--success {
filter: saturate(2.5) brightness(0.85); filter: saturate(2.5) brightness(0.85);
} }
} }

View file

@ -180,8 +180,6 @@
display: block; display: block;
padding: 1rem; padding: 1rem;
width: 100%; width: 100%;
overflow: auto;
max-height: var(--code-max-height);
} }
&__align { &__align {

View file

@ -62,7 +62,7 @@
} }
.hidden { .hidden {
display: none; display: none !important;
} }
.svg-sprite { .svg-sprite {

View file

@ -1,3 +1,5 @@
@use "sass:map";
@import "_defaults"; @import "_defaults";
@import "_color_mode"; @import "_color_mode";
@import "_chroma_base"; @import "_chroma_base";