From 75f56d8fada1a3e4eba2af77dbb27703a039e6fb Mon Sep 17 00:00:00 2001 From: Robert Kaussow Date: Sun, 7 Nov 2021 22:12:14 +0100 Subject: [PATCH] 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/). --- exampleSite/content/features/code-blocks.md | 6 ++-- exampleSite/static/custom.css.example | 16 +++++++++ layouts/partials/foot.html | 2 ++ src/icons/check.svg | 5 +++ src/icons/copy.svg | 5 +++ src/js/clipboard-loader.js | 18 ++++++++++ src/js/copycode.js | 34 ++++++++++++++++++ src/sass/_base.scss | 39 +++++++++++++++++++++ src/sass/_chroma_base.scss | 3 ++ src/sass/_color_mode.scss | 11 +++++- src/sass/_markdown.scss | 2 -- src/sass/_utils.scss | 2 +- src/sass/main.scss | 2 ++ 13 files changed, 138 insertions(+), 7 deletions(-) create mode 100644 src/icons/check.svg create mode 100644 src/icons/copy.svg create mode 100644 src/js/copycode.js diff --git a/exampleSite/content/features/code-blocks.md b/exampleSite/content/features/code-blocks.md index abd0ccc..6ed21ca 100644 --- a/exampleSite/content/features/code-blocks.md +++ b/exampleSite/content/features/code-blocks.md @@ -2,7 +2,7 @@ title: Code Blocks --- -There are multiple ways to add code blocks. Most of them works out of the box only the Hugo shortcode `` 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 `` 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 >}} @@ -21,14 +21,14 @@ To display an inline shortcode use single quotes: Code blocks can be uses without language specification: ````markdown -``` +```Plain some code ``` ```` **Example:** -```plain +```Plain some code ``` diff --git a/exampleSite/static/custom.css.example b/exampleSite/static/custom.css.example index c0a189a..d395703 100644 --- a/exampleSite/static/custom.css.example +++ b/exampleSite/static/custom.css.example @@ -23,6 +23,10 @@ --code-accent-color: #e3e7eb; --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-lite: #f8f9fa; @@ -51,6 +55,10 @@ --code-accent-color: #e3e7eb; --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-lite: #f8f9fa; @@ -81,6 +89,10 @@ --code-accent-color: #262b2f; --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-lite: #2f353a; @@ -109,6 +121,10 @@ --code-accent-color: #262b2f; --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-lite: #2f353a; diff --git a/layouts/partials/foot.html b/layouts/partials/foot.html index 2a8def8..217b78e 100644 --- a/layouts/partials/foot.html +++ b/layouts/partials/foot.html @@ -10,3 +10,5 @@ {{ end }} + + diff --git a/src/icons/check.svg b/src/icons/check.svg new file mode 100644 index 0000000..6240dc3 --- /dev/null +++ b/src/icons/check.svg @@ -0,0 +1,5 @@ + + +check + + diff --git a/src/icons/copy.svg b/src/icons/copy.svg new file mode 100644 index 0000000..e54473d --- /dev/null +++ b/src/icons/copy.svg @@ -0,0 +1,5 @@ + + +copy + + diff --git a/src/js/clipboard-loader.js b/src/js/clipboard-loader.js index 9fa843b..b2a8de6 100644 --- a/src/js/clipboard-loader.js +++ b/src/js/clipboard-loader.js @@ -1,3 +1,21 @@ document.addEventListener("DOMContentLoaded", function (event) { 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(); + }); }); diff --git a/src/js/copycode.js b/src/js/copycode.js new file mode 100644 index 0000000..4543eab --- /dev/null +++ b/src/js/copycode.js @@ -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 = + '' + + ''; + 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)); diff --git a/src/sass/_base.scss b/src/sass/_base.scss index f10179a..31ef857 100644 --- a/src/sass/_base.scss +++ b/src/sass/_base.scss @@ -488,6 +488,45 @@ img { 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 { diff --git a/src/sass/_chroma_base.scss b/src/sass/_chroma_base.scss index 053c453..c8fdcc8 100644 --- a/src/sass/_chroma_base.scss +++ b/src/sass/_chroma_base.scss @@ -35,6 +35,9 @@ } .highlight { + overflow: auto; + max-height: var(--code-max-height); + pre.chroma { margin: 0; } diff --git a/src/sass/_color_mode.scss b/src/sass/_color_mode.scss index 89312e0..b4c6772 100644 --- a/src/sass/_color_mode.scss +++ b/src/sass/_color_mode.scss @@ -18,6 +18,10 @@ --code-accent-color-lite: #{darken($code-background, 2)}; --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-lite: #{$gray-100}; @@ -61,6 +65,10 @@ --code-accent-color-lite: #{darken($code-background-dark, 2)}; --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-lite: #{darken($body-background-dark, 2)}; @@ -78,7 +86,8 @@ } .gdoc-markdown { - .gdoc-hint { + .gdoc-hint, + .gdoc-post__codecopy--success { filter: saturate(2.5) brightness(0.85); } } diff --git a/src/sass/_markdown.scss b/src/sass/_markdown.scss index 186fe46..905a13a 100644 --- a/src/sass/_markdown.scss +++ b/src/sass/_markdown.scss @@ -180,8 +180,6 @@ display: block; padding: 1rem; width: 100%; - overflow: auto; - max-height: var(--code-max-height); } &__align { diff --git a/src/sass/_utils.scss b/src/sass/_utils.scss index e04a716..c65bb56 100644 --- a/src/sass/_utils.scss +++ b/src/sass/_utils.scss @@ -62,7 +62,7 @@ } .hidden { - display: none; + display: none !important; } .svg-sprite { diff --git a/src/sass/main.scss b/src/sass/main.scss index 746ed9a..87d51c4 100644 --- a/src/sass/main.scss +++ b/src/sass/main.scss @@ -1,3 +1,5 @@ +@use "sass:map"; + @import "_defaults"; @import "_color_mode"; @import "_chroma_base";