Add code copy button to all code fields in the blog (#81)
This commit is contained in:
1 parent
a9f2ddcfa9
commit
16c9d78ae5
10 files changed
+110
-6
No files matched your search
@@ -13,6 +13,7 @@ Hermit is a minimal and fast theme for Hugo. It's built for bloggers who want a
|
||||
* Featured image is supported. It will be displayed as a dimmed background of the page.
|
||||
* Displays all of your posts on a single page, with one section per year, simple and compact.
|
||||
* Extremely lightweight and load fast. No third party framework, no unnecessary code.
|
||||
* All code fields feature syntax highlighting and a code-copy function
|
||||
* Responsive & Retina Ready. Scales gracefully from a big screen all the way down to the smallest mobile phone. Assets in vector format ensures that it looks sharp on high-resolution screens.
|
||||
|
||||
**[Theme Demo](https://hugo-theme-hermit.netlify.com/)** (uses contents and config from the `exampleSite` folder)
|
||||
@@ -111,5 +112,6 @@ You can inject any html code to every page's document head or right above the cl
|
||||
* [normalize.css](https://necolas.github.io/normalize.css/) - [MIT](https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
* [animate.css](https://daneden.github.io/animate.css/) - [MIT](https://github.com/daneden/animate.css/blob/master/LICENSE)
|
||||
* [feather](https://feathericons.com/) - [MIT](https://github.com/feathericons/feather/blob/master/LICENSE)
|
||||
* [code-copy.js](assets/js/code-copy.js) - [Tom Spencer](https://www.fiznool.com/blog/2018/09/14/adding-click-to-copy-buttons-to-a-hugo-powered-blog/)
|
||||
|
||||
Thanks!
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Utils
|
||||
*/
|
||||
|
||||
// Add code-copy buttons using progressive enhancement
|
||||
// © 2019. Tom Spencer
|
||||
// https://www.fiznool.com/blog/2018/09/14/adding-click-to-copy-buttons-to-a-hugo-powered-blog/
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
if(!document.queryCommandSupported('copy')) {
|
||||
return;
|
||||
}
|
||||
|
||||
function flashCopyMessage(el, msg) {
|
||||
el.textContent = msg;
|
||||
setTimeout(function() {
|
||||
el.textContent = "Copy";
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function selectText(node) {
|
||||
var selection = window.getSelection();
|
||||
var range = document.createRange();
|
||||
range.selectNodeContents(node);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
return selection;
|
||||
}
|
||||
|
||||
function addCopyButton(containerEl) {
|
||||
var copyBtn = document.createElement("button");
|
||||
copyBtn.className = "highlight-copy-btn";
|
||||
copyBtn.textContent = "Copy";
|
||||
|
||||
var codeEl = containerEl.firstElementChild;
|
||||
copyBtn.addEventListener('click', function() {
|
||||
try {
|
||||
var selection = selectText(codeEl);
|
||||
document.execCommand('copy');
|
||||
selection.removeAllRanges();
|
||||
|
||||
flashCopyMessage(copyBtn, 'Copied!')
|
||||
} catch(e) {
|
||||
console && console.log(e);
|
||||
flashCopyMessage(copyBtn, 'Failed :\'(')
|
||||
}
|
||||
});
|
||||
|
||||
containerEl.appendChild(copyBtn);
|
||||
}
|
||||
|
||||
// Add copy button to code blocks
|
||||
var highlightBlocks = document.getElementsByClassName('highlight');
|
||||
Array.prototype.forEach.call(highlightBlocks, addCopyButton);
|
||||
})();
|
||||
@@ -153,6 +153,37 @@ table {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Code copy buttons
|
||||
//
|
||||
|
||||
.highlight {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.highlight pre {
|
||||
padding-right: 75px;
|
||||
}
|
||||
|
||||
.highlight-copy-btn {
|
||||
position: absolute;
|
||||
bottom: 7px;
|
||||
right: 7px;
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
padding: 1px;
|
||||
font-size: 0.7em;
|
||||
line-height: 1.8;
|
||||
color: #fff;
|
||||
background-color: #777;
|
||||
opacity: 0.6;
|
||||
min-width: 55px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.highlight-copy-btn:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
// Accessibility
|
||||
//
|
||||
.screen-reader-text {
|
||||
|
||||
@@ -48,6 +48,8 @@ enableEmoji = true # Shorthand emojis in content files - https://gohugo.io/func
|
||||
|
||||
relatedPosts = false # Add a related content section to all single posts page
|
||||
|
||||
code_copy_button = true # Turn on/off the code-copy-button for code-fields
|
||||
|
||||
# Add custom css
|
||||
# customCSS = ["css/foo.css", "css/bar.css"]
|
||||
|
||||
|
||||
@@ -30,8 +30,17 @@
|
||||
{{ block "header" . -}}{{ end -}}
|
||||
{{ block "main" . -}}{{ end -}}
|
||||
{{ block "footer" . -}}{{ end }}
|
||||
{{ $script := resources.Get "js/main.js" | minify | fingerprint -}}
|
||||
<script src="{{ $script.Permalink }}" {{ printf "integrity=%q" $script.Data.Integrity | safeHTMLAttr }} crossorigin="anonymous"></script>
|
||||
|
||||
{{ $main := resources.Get "js/main.js" -}}
|
||||
{{ if .Site.Params.code_copy_button | default true -}}
|
||||
{{ $codeCopy := resources.Get "js/code-copy.js" -}}
|
||||
{{ $script := slice $main $codeCopy | resources.Concat "js/bundle.js" | minify | fingerprint -}}
|
||||
<script src="{{ $script.Permalink }}" {{ printf "integrity=%q" $script.Data.Integrity | safeHTMLAttr }} crossorigin="anonymous"></script>
|
||||
{{ else -}}
|
||||
{{ $script := $main | minify | fingerprint -}}
|
||||
<script src="{{ $script.Permalink }}" {{ printf "integrity=%q" $script.Data.Integrity | safeHTMLAttr }} crossorigin="anonymous"></script>
|
||||
{{ end }}
|
||||
|
||||
{{- partial "analytics.html" . }}
|
||||
{{- if templates.Exists "partials/extra-foot.html" -}}
|
||||
{{ partial "extra-foot.html" . }}
|
||||
|
||||
+5
-1
@@ -6,4 +6,8 @@ mobileMenuVisible=false;}}
|
||||
const showImg=()=>{document.querySelector('.bg-img').classList.add('show-bg-img');}
|
||||
const hideImg=()=>{document.querySelector('.bg-img').classList.remove('show-bg-img');}
|
||||
const toggleToc=()=>{document.getElementById('toc').classList.toggle('show-toc');}
|
||||
if(header!==null){listen('#menu-btn',"click",toggleMobileMenu);listen('#toc-btn',"click",toggleToc);listen('#img-btn',"click",showImg);listen('.bg-img',"click",hideImg);document.querySelectorAll('.post-year').forEach((ele)=>{ele.addEventListener('click',()=>{window.location.hash='#'+ele.id;});});window.addEventListener('scroll',throttle(()=>{autoHideHeader();if(mobileMenuVisible==true){toggleMobileMenu();}},250));}
|
||||
if(header!==null){listen('#menu-btn',"click",toggleMobileMenu);listen('#toc-btn',"click",toggleToc);listen('#img-btn',"click",showImg);listen('.bg-img',"click",hideImg);document.querySelectorAll('.post-year').forEach((ele)=>{ele.addEventListener('click',()=>{window.location.hash='#'+ele.id;});});window.addEventListener('scroll',throttle(()=>{autoHideHeader();if(mobileMenuVisible==true){toggleMobileMenu();}},250));};(function(){'use strict';if(!document.queryCommandSupported('copy')){return;}
|
||||
function flashCopyMessage(el,msg){el.textContent=msg;setTimeout(function(){el.textContent="Copy";},1000);}
|
||||
function selectText(node){var selection=window.getSelection();var range=document.createRange();range.selectNodeContents(node);selection.removeAllRanges();selection.addRange(range);return selection;}
|
||||
function addCopyButton(containerEl){var copyBtn=document.createElement("button");copyBtn.className="highlight-copy-btn";copyBtn.textContent="Copy";var codeEl=containerEl.firstElementChild;copyBtn.addEventListener('click',function(){try{var selection=selectText(codeEl);document.execCommand('copy');selection.removeAllRanges();flashCopyMessage(copyBtn,'Copied!')}catch(e){console&&console.log(e);flashCopyMessage(copyBtn,'Failed :\'(')}});containerEl.appendChild(copyBtn);}
|
||||
var highlightBlocks=document.getElementsByClassName('highlight');Array.prototype.forEach.call(highlightBlocks,addCopyButton);})();
|
||||
@@ -0,0 +1 @@
|
||||
{"Target":"js/bundle.min.4a9a0ac3d2217822c7865b4161e6c2a71de1d70492264337755427898dd718f6.js","MediaType":"application/javascript","Data":{"Integrity":"sha256-SpoKw9IheCLHhltBYebCpx3h1wSSJkM3dVQniY3XGPY="}}
|
||||
@@ -1 +0,0 @@
|
||||
{"Target":"js/main.min.35ccbf1cdceb91e4c64c06b5d009d6e2977fafe56beda7762febd4e67528d2ac.js","MediaType":"application/javascript","Data":{"Integrity":"sha256-Ncy/HNzrkeTGTAa10AnW4pd/r+Vr7ad2L+vU5nUo0qw="}}
|
||||
Regular → Executable
+1
-1
@@ -2,4 +2,4 @@
|
||||
* Version - 3.7.0
|
||||
* Licensed under the MIT license - http://opensource.org/licenses/MIT
|
||||
*
|
||||
* Copyright (c) 2019 Daniel Eden*/@-webkit-keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}@keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(0.215,0.61,0.355,1);animation-timing-function:cubic-bezier(0.215,0.61,0.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(0.215,0.61,0.355,1);animation-timing-function:cubic-bezier(0.215,0.61,0.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInUp{-webkit-animation-name:slideInUp;animation-name:slideInUp}@-webkit-keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.slideOutDown{-webkit-animation-name:slideOutDown;animation-name:slideOutDown}.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.delay-1s{-webkit-animation-delay:1s;animation-delay:1s}.animated.delay-2s{-webkit-animation-delay:2s;animation-delay:2s}.animated.delay-3s{-webkit-animation-delay:3s;animation-delay:3s}.animated.delay-4s{-webkit-animation-delay:4s;animation-delay:4s}.animated.delay-5s{-webkit-animation-delay:5s;animation-delay:5s}.animated.fast{-webkit-animation-duration:.8s;animation-duration:.8s}.animated.faster{-webkit-animation-duration:.5s;animation-duration:.5s}.animated.slow{-webkit-animation-duration:2s;animation-duration:2s}.animated.slower{-webkit-animation-duration:3s;animation-duration:3s}@media(prefers-reduced-motion),(print){.animated{-webkit-animation:unset!important;animation:unset!important;-webkit-transition:none!important;transition:none!important}}::-webkit-scrollbar{width:8px;height:8px;background:#2c3e50}::-webkit-scrollbar-thumb{background:#888}::-webkit-scrollbar-thumb:hover{background:#e8eef2}html{background:#494f5c;line-height:1.6;letter-spacing:.06em;scroll-behavior:smooth}body,button,input,select,textarea{color:#e8eef2;font-family:trebuchet ms,Verdana,verdana ref,segoe ui,Candara,lucida grande,lucida sans unicode,lucida sans,Tahoma,sans-serif}pre,code,pre tt{font-family:Consolas,andale mono wt,andale mono,Menlo,Monaco,lucida console,lucida sans typewriter,dejavu sans mono,bitstream vera sans mono,liberation mono,nimbus mono l,courier new,Courier,yahei consolas hybrid,monospace,segoe ui emoji,pingfang sc,microsoft yahei}pre{padding:.7em 1.1em;overflow:auto;font-size:.9em;line-height:1.5;letter-spacing:normal;white-space:pre;color:#eee;background:#2c3e50;border-radius:4px}pre code{padding:0;margin:0;background:#2c3e50}code{color:#eee;background:#7d828a;border-radius:3px;padding:0 3px;margin:0 4px;word-wrap:break-word;letter-spacing:normal}blockquote{border-left:.25em solid;margin:1em;paddingLine truncated
|
||||
* Copyright (c) 2019 Daniel Eden*/@-webkit-keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}@keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(0.215,0.61,0.355,1);animation-timing-function:cubic-bezier(0.215,0.61,0.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(0.215,0.61,0.355,1);animation-timing-function:cubic-bezier(0.215,0.61,0.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInUp{-webkit-animation-name:slideInUp;animation-name:slideInUp}@-webkit-keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.slideOutDown{-webkit-animation-name:slideOutDown;animation-name:slideOutDown}.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.delay-1s{-webkit-animation-delay:1s;animation-delay:1s}.animated.delay-2s{-webkit-animation-delay:2s;animation-delay:2s}.animated.delay-3s{-webkit-animation-delay:3s;animation-delay:3s}.animated.delay-4s{-webkit-animation-delay:4s;animation-delay:4s}.animated.delay-5s{-webkit-animation-delay:5s;animation-delay:5s}.animated.fast{-webkit-animation-duration:.8s;animation-duration:.8s}.animated.faster{-webkit-animation-duration:.5s;animation-duration:.5s}.animated.slow{-webkit-animation-duration:2s;animation-duration:2s}.animated.slower{-webkit-animation-duration:3s;animation-duration:3s}@media(prefers-reduced-motion),(print){.animated{-webkit-animation:unset!important;animation:unset!important;-webkit-transition:none!important;transition:none!important}}::-webkit-scrollbar{width:8px;height:8px;background:#2c3e50}::-webkit-scrollbar-thumb{background:#888}::-webkit-scrollbar-thumb:hover{background:#e8eef2}html{background:#494f5c;line-height:1.6;letter-spacing:.06em;scroll-behavior:smooth}body,button,input,select,textarea{color:#e8eef2;font-family:trebuchet ms,Verdana,verdana ref,segoe ui,Candara,lucida grande,lucida sans unicode,lucida sans,Tahoma,sans-serif}pre,code,pre tt{font-family:Consolas,andale mono wt,andale mono,Menlo,Monaco,lucida console,lucida sans typewriter,dejavu sans mono,bitstream vera sans mono,liberation mono,nimbus mono l,courier new,Courier,yahei consolas hybrid,monospace,segoe ui emoji,pingfang sc,microsoft yahei}pre{padding:.7em 1.1em;overflow:auto;font-size:.9em;line-height:1.5;letter-spacing:normal;white-space:pre;color:#eee;background:#2c3e50;border-radius:4px}pre code{padding:0;margin:0;background:#2c3e50}code{color:#eee;background:#7d828a;border-radius:3px;padding:0 3px;margin:0 4px;word-wrap:break-word;letter-spacing:normal}blockquote{border-left:.25em solid;margin:1em;paddingLine truncated
|
||||
Regular → Executable
+1
-1
@@ -1 +1 @@
|
||||
{"Target":"css/style.min.568c54a56780af2a70c45272522247710b69dbfc080b315211fb98381e3796f8.css","MediaType":"text/css","Data":{"Integrity":"sha256-VoxUpWeArypwxFJyUiJHcQtp2/wICzFSEfuYOB43lvg="}}
|
||||
{"Target":"css/style.min.5ee5e7976cd09872c64e40a582206543f6aa38c69a8c43898aadc70040344b92.css","MediaType":"text/css","Data":{"Integrity":"sha256-XuXnl2zQmHLGTkClgiBlQ/aqOMaajEOJiq3HAEA0S5I="}}
|
||||
Reference in new issue
Block a user