Skip to content

Commit 12cb92c

Browse files
feat: Add "copy code" buttons to code blocks.
1 parent f713833 commit 12cb92c

3 files changed

Lines changed: 102 additions & 2 deletions

File tree

assets/sass/styles.scss

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,14 @@ article {
238238
}
239239
}
240240

241-
code {
242-
font-family: "Courier Prime", monospace;
241+
pre {
242+
border-radius: 0;
243+
padding: 6px 12px;
244+
margin: 0;
245+
246+
code {
247+
font-family: "Courier Prime", monospace;
248+
}
243249
}
244250

245251
.backtotop {
@@ -276,3 +282,18 @@ footer {
276282
}
277283
}
278284
}
285+
286+
.copy-code-button {
287+
color: black;
288+
background-color: lighten($background-color, 5%);
289+
border: 2px solid darken($link-color, 10%);
290+
291+
width: 90px;
292+
font-size: 0.9em;
293+
294+
&:hover {
295+
cursor: pointer;
296+
background-color: darken($background-color, 5%);
297+
transition: background-color 0.1s ease-in;
298+
}
299+
}

layouts/_default/baseof.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@
99
</div>
1010
{{- partial "footer.html" . -}}
1111
</body>
12+
13+
<!-- Copy code buttons: https://www.dannyguo.com/blog/how-to-add-copy-to-clipboard-buttons-to-code-blocks-in-hugo/ -->
14+
<script src="{{ "copy_code.js" | relURL }}" defer></script>
1215
</html>

static/copy_code.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
const codeBlockButtonPairs = [];
2+
3+
function addCopyButtons(clipboard) {
4+
document.querySelectorAll('pre > code').forEach(function (codeBlock) {
5+
var button = document.createElement('button');
6+
button.className = 'copy-code-button';
7+
button.type = 'button';
8+
button.innerText = 'Copy code';
9+
10+
button.style.position = 'absolute';
11+
12+
button.addEventListener('click', function () {
13+
clipboard.writeText(codeBlock.textContent).then(function () {
14+
/* Chrome doesn't seem to blur automatically,
15+
leaving the button in a focused state. */
16+
button.blur();
17+
18+
button.innerText = 'Copied!';
19+
20+
setTimeout(function () {
21+
button.innerText = 'Copy code';
22+
}, 2000);
23+
}, function (error) {
24+
button.innerText = 'Error';
25+
});
26+
});
27+
28+
var pre = codeBlock.parentNode;
29+
if (pre.parentNode.classList.contains('highlight')) {
30+
var highlight = pre.parentNode;
31+
highlight.parentNode.insertBefore(button, highlight);
32+
} else {
33+
pre.parentNode.insertBefore(button, pre);
34+
}
35+
36+
codeBlockButtonPairs.push({codeBlock, button});
37+
});
38+
}
39+
40+
if (navigator && navigator.clipboard) {
41+
addCopyButtons(navigator.clipboard);
42+
} else {
43+
var script = document.createElement('script');
44+
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/clipboard-polyfill/2.7.0/clipboard-polyfill.promise.js';
45+
script.integrity = 'sha256-waClS2re9NUbXRsryKoof+F9qc1gjjIhc2eT7ZbIv94=';
46+
script.crossOrigin = 'anonymous';
47+
script.onload = function() {
48+
addCopyButtons(clipboard);
49+
};
50+
51+
document.body.appendChild(script);
52+
}
53+
54+
function positionButtons() {
55+
codeBlockButtonPairs.forEach(({ codeBlock, button }) => {
56+
const rect = codeBlock.getBoundingClientRect();
57+
const codeBlockStyle = window.getComputedStyle(codeBlock.parentNode);
58+
const buttonStyle = window.getComputedStyle(button);
59+
const articleStyle = window.getComputedStyle(document.querySelector('article'));
60+
61+
const horizontalShift = parseFloat(codeBlockStyle.getPropertyValue('padding-left').slice(0, -2)) +
62+
parseFloat(buttonStyle.getPropertyValue('width').slice(0, -2)) +
63+
2 * parseFloat(articleStyle.getPropertyValue('padding-left').slice(0, -2)) +
64+
-0.8; // Weird correction term, not sure what's up with this.
65+
console.log(`horizontalShift: ${horizontalShift}`);
66+
button.style.top = `${window.scrollY + rect.top - 20.3}px`;
67+
button.style.left = `${window.scrollX + rect.left - horizontalShift}px`;
68+
});
69+
}
70+
71+
// Initial placement
72+
positionButtons();
73+
74+
// Re-position when scrolling or resizing
75+
window.addEventListener("resize", positionButtons);
76+
window.addEventListener("scroll", positionButtons);

0 commit comments

Comments
 (0)