From b46e1edb90dd6853071bc857dc58e9d4e12452aa Mon Sep 17 00:00:00 2001 From: XPoet Date: Sat, 18 Apr 2020 17:26:29 +0800 Subject: [PATCH] feat: add code block copy feature --- _config.yml | 10 ++++- layout/_partial/scripts.ejs | 10 ++++- .../{highlight => codeblock}/code-theme.styl | 0 .../{highlight => codeblock}/highlight.styl | 4 +- source/css/layout/common/variables.styl | 2 +- source/css/style.styl | 3 +- source/js/code-copy.js | 45 +++++++++++++++++++ 7 files changed, 68 insertions(+), 6 deletions(-) rename source/css/layout/common/{highlight => codeblock}/code-theme.styl (100%) rename source/css/layout/common/{highlight => codeblock}/highlight.styl (99%) create mode 100644 source/js/code-copy.js diff --git a/_config.yml b/_config.yml index d3419db..9cf2c9b 100644 --- a/_config.yml +++ b/_config.yml @@ -15,7 +15,7 @@ menu: # RSS rss: - enable: false + enable: true # favicon favicon: images/favicon.png @@ -66,4 +66,10 @@ local_search: # Unescape html strings to the readable one. unescape: false # Preload the search data when the page loads. - preload: false \ No newline at end of file + preload: false + +# Code Block +codeblock: + style: flat # Available values: default | flat | mac + copy_button: + enable: true diff --git a/layout/_partial/scripts.ejs b/layout/_partial/scripts.ejs index 570f50e..dc31d2a 100644 --- a/layout/_partial/scripts.ejs +++ b/layout/_partial/scripts.ejs @@ -1 +1,9 @@ -<%- js(['js/main.js', 'js/header-shrink.js', 'js/toggle-mode.js', 'js/scroll-to-top.js']) %> \ No newline at end of file +<%- js([ + 'js/main.js', + 'js/header-shrink.js', + 'js/toggle-mode.js', + 'js/scroll-to-top.js' +]) %> +<% if (theme.codeblock.copy_button.enable) { %> + <%- js('js/code-copy.js') %> +<% } %> \ No newline at end of file diff --git a/source/css/layout/common/highlight/code-theme.styl b/source/css/layout/common/codeblock/code-theme.styl similarity index 100% rename from source/css/layout/common/highlight/code-theme.styl rename to source/css/layout/common/codeblock/code-theme.styl diff --git a/source/css/layout/common/highlight/highlight.styl b/source/css/layout/common/codeblock/highlight.styl similarity index 99% rename from source/css/layout/common/highlight/highlight.styl rename to source/css/layout/common/codeblock/highlight.styl index 2f0aad9..2b9a872 100644 --- a/source/css/layout/common/highlight/highlight.styl +++ b/source/css/layout/common/codeblock/highlight.styl @@ -15,7 +15,7 @@ $code-block { } &::-webkit-scrollbar-thumb { - border-radius: 5px; + border-radius: 1px; background: rgba(0, 0, 0, 0.3) } @@ -60,6 +60,7 @@ pre { padding: 10px 0; } + table { margin: 0; width: auto; @@ -67,6 +68,7 @@ pre { border-spacing: unset; } + td { border: none; padding: 0; diff --git a/source/css/layout/common/variables.styl b/source/css/layout/common/variables.styl index 98dae2f..899b1dd 100644 --- a/source/css/layout/common/variables.styl +++ b/source/css/layout/common/variables.styl @@ -25,7 +25,7 @@ $z-index-6 = 1006; // color // =============================== // normal mode color -$primary-color = #f04c12; // 主题颜色 +$primary-color = #1b65ea; // 主题颜色 $background-color = #fdfdfd; // 背景颜色 $normal-text-color = #44424e; // 通用文本颜色(默认字体颜色) $first-text-color = darken($normal-text-color, 15%); // 第一文本颜色 diff --git a/source/css/style.styl b/source/css/style.styl index 7393070..c5148a0 100644 --- a/source/css/style.styl +++ b/source/css/style.styl @@ -16,4 +16,5 @@ @import "layout/category-content.styl" @import "layout/tag-content.styl" @import "layout/common/markdown.styl" -@import "layout/common/highlight/highlight.styl" \ No newline at end of file +@import "layout/common/codeblock/highlight.styl" +@import "layout/common/codeblock/copy-code.styl" \ No newline at end of file diff --git a/source/js/code-copy.js b/source/js/code-copy.js new file mode 100644 index 0000000..5e09bc9 --- /dev/null +++ b/source/js/code-copy.js @@ -0,0 +1,45 @@ +HTMLElement.prototype.wrap = function (wrapper) { + this.parentNode.insertBefore(wrapper, this); + this.parentNode.removeChild(this); + wrapper.appendChild(this); +}; + +window.addEventListener('DOMContentLoaded', () => { + document.querySelectorAll('figure.highlight').forEach(element => { + const box = document.createElement('div'); + element.wrap(box); + box.classList.add('highlight-container'); + box.insertAdjacentHTML('beforeend', '
'); + var button = element.parentNode.querySelector('.copy-btn'); + button.addEventListener('click', event => { + var target = event.currentTarget; + var code = [...target.parentNode.querySelectorAll('.code .line')].map(line => line.innerText).join('\n'); + var ta = document.createElement('textarea'); + ta.style.top = window.scrollY + 'px'; // Prevent page scrolling + ta.style.position = 'absolute'; + ta.style.opacity = '0'; + ta.readOnly = true; + ta.value = code; + document.body.append(ta); + const selection = document.getSelection(); + const selected = selection.rangeCount > 0 ? selection.getRangeAt(0) : false; + ta.select(); + ta.setSelectionRange(0, code.length); + ta.readOnly = false; + var result = document.execCommand('copy'); + target.querySelector('i').className = result ? 'fa fa-check' : 'fa fa-times'; + ta.blur(); // For iOS + target.blur(); + if (selected) { + selection.removeAllRanges(); + selection.addRange(selected); + } + document.body.removeChild(ta); + }); + button.addEventListener('mouseleave', event => { + setTimeout(() => { + event.target.querySelector('i').className = 'fa fa-clipboard'; + }, 300); + }); + }); +});