diff --git a/layouts/blog/single.html b/layouts/blog/single.html
index 880fc66..9da19a8 100644
--- a/layouts/blog/single.html
+++ b/layouts/blog/single.html
@@ -37,3 +37,10 @@
{{ .Title }}
{{ end }}
+
+{{ define "js-extra" }}
+ {{ if (findRE "class=\"highlight\"" .Content 1) }}
+
+
+ {{ end }}
+{{ end }}
diff --git a/static/css/post.css b/static/css/post.css
index fe40089..42f7296 100644
--- a/static/css/post.css
+++ b/static/css/post.css
@@ -24,3 +24,38 @@ h1 {
text-align: right;
width: 48%;
}
+
+.copy-code-button {
+ color: #272822;
+ background-color: #FFF;
+ border-color: #272822;
+ border: 2px solid;
+ border-radius: 3px;
+
+ /* right-align */
+ display: block;
+ margin-left: auto;
+ margin-right: 0;
+
+ /* for some reason, there is space between the button and the code block */
+ margin-bottom: -10px;
+
+ padding: 3px 8px;
+ font-size: 0.8em;
+}
+
+.copy-code-button:hover {
+ cursor: pointer;
+ background-color: #F2F2F2;
+}
+
+.copy-code-button:focus {
+ /* avoid an ugly focus outline on click in Chrome, but darken the button
+ for accessibility. https://stackoverflow.com/a/25298082/1481479 */
+ background-color: #E6E6E6;
+ outline: 0;
+}
+
+.copy-code-button:active {
+ background-color: #D9D9D9;
+}
diff --git a/static/js/copy-code-button.js b/static/js/copy-code-button.js
new file mode 100644
index 0000000..fcecc34
--- /dev/null
+++ b/static/js/copy-code-button.js
@@ -0,0 +1,26 @@
+if (clipboard) {
+ document.querySelectorAll('.highlight').forEach(function (codeBlock) {
+ var button = document.createElement('button');
+
+ button.className = 'copy-code-button';
+ button.type = 'button';
+ button.innerText = 'Copy';
+
+ button.addEventListener('click', function () {
+ clipboard.writeText(codeBlock.innerText).then(function () {
+ /* Chrome doesn't seem to blur automatically, leaving the button
+ in a focused state */
+ button.blur();
+
+ button.innerText = 'Copied!';
+ setTimeout(function () {
+ button.innerText = 'Copy';
+ }, 2000);
+ }, function (error) {
+ button.innerText = 'Error';
+ });
+ });
+
+ codeBlock.parentNode.insertBefore(button, codeBlock);
+ });
+}