Skip to content

Commit efba0cf

Browse files
committed
Make copying code blocks easier
When hovering over code blocks, we now show a copy button. When clicked, the textual representation of a code block is copied to the clipboard.
1 parent 46b1854 commit efba0cf

File tree

5 files changed

+87
-5
lines changed

5 files changed

+87
-5
lines changed

docs/source/css/icons.css

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@font-face {
22
font-family: 'icons';
3-
src: url(data:font/woff2;base64,d09GMgABAAAAAAUEAAsAAAAACLQAAAS5AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmAAdBEIColYiDQLFAABNgIkAyQEIAWCbgcgGzsHID4NcHK76gfI8srYRpikabpkmJAS9kTyyUHXefpFSA4e+v3Rn4sFNZ0drqCb74vrvEnsauu0s8nJDfw/vz/yPl/iSRYSb8SJUpnf+tRjZ4fG5d1TaNBApS2qEQxp1aFt2uWloSc0Fi/gLtFJgfRrkYzSXk/4p4fHrjCJLEiy4oRSDHGehgTy+3/ga2tqqRkmQA9bAo/3D38/00UURtuABzijt/cXVVhpUbhLwAS5AV1EWpXI8R3YqYDnyCqdL14BpYLEFDgAch59Bua6ScQbyQJPp094s24a8L1DG2mKQBgBLkS7VJgKB7JcJAgbRdT/9oUGEhQEpe80ZA1Avb2w8zr12hEcFqwVlJ/YyCEqQMABXjHFBacvqYgFQK4YIQtp2DiYCAVTJzoHONCjheTkhST19UVV3JDhc0oLI4KAhe20Fght3SzdPQdMIrb3cV3fIowoTmPgsFlikYjIvkNi+wyb9iyDXgH3M4rGJ7tBH2YRVuGf6oMxwgp0udqagi9XY7HrZAR3IxZWJO9W7DYV/vXaOcxNDWpc9bS8RbGqACeXXlYsceVFbqixLf573GqevrjmpllwpJcDFvrefib9vtEy3Wf5fXoNxeazYP1dn3pYYK6bk2c5FxfYuyZMclnz+8R2y5sXfLX9f9AaFbxf0GnmCG29sJZjrH2d9lfgZhlMr56HVzI7nk1nYFZ9WmCPX8XETZ51cYnbtyBrvujOvojmB4CprBDVE30I/QWr7VBQA2v7uHkwxA/lGmc54cqfG8689IfblPfDtZzDcNbLdDY2OpG3t72OMNnkgEz3MTcXFkNbqSMiPcZsT0n3/4+ZXZNPCxy2ViWU96jKgVOK4M7AQP/wCxW8VsvpZdoygT6m9uJonNNK5duzLEixzjYgMS97ZleBct0Cp5P8f5WKQOXAigoaVYmNjUEPRKgEoaEaZYLxQpAdLChmHDuFNbzuu7GrdL7zKUVIJ/QDrcAFNShVjHAy3qdrY5TFMFyD4xOd7XxEgEkB2P/7914S2V3CZMTKrANVlza7LqTjFgmSQ+6o9iWiDal0h6Fe0d7+0DAwEIFbbaZjIRVumKfXIqJDkoA9SLoYvDnJVrMqFZMJaNXi9WmSwfl9nnRwChVL9mvJlMgN89SMqPaE6QWzUmVWPktaQkBTd9Us0zWM1TVSfu/u0NDMy31PtOnKuYtVC7d+Nhc61jvSR/88Qfdi7nLeenJ+fw+jyP72j10bWjNSGMrdrhtRogqp/Reh8PcRX8lR4dTdbwByS2b0/twdvOcPjmvq2XSN5Tq7GFtaGLuwfzk2AcYNAGygDgO6atDRQ9OQZX5cAORWL+f+F/rvTNQA8PT6P7S4teAMCmTIGaEThzG6RTPPRYtkpE81EFwPNJNlvk8ATlBNCbvRQ8KT1QrCUwQgKiQUAQoFgRFa41MVDrAIKhwhcDzeFRk6wUC0CwgMRKBAESBcgcFgjsbxWQoCCQQKEga3AoMZY5du25VCNqkUUkDpLd91jA2MoIh0SrAj2WRK2LFgcxmlMb2p3i9BCOlkUk4eyZT08L7+odtHVm8M/AsVAxADtZehRDPpFCyCZjJlpJPWXEc1SiRnl/CnsF65AUgG);
3+
src: url(data:font/woff2;base64,d09GMgABAAAAAAVIAAsAAAAACWgAAAT6AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmAAdBEICosEiT8LFgABNgIkAygEIAWCbgcgG8oHIB6HsXvknFHsX5N8+HfTPzcJ0qSF8l4KNTWqxrQmTA02h82RqcJMDHhi+k09wTew2W3/oWulMxcRFi16gGc0O5dz2R/dVuAJ8gf0URhNgVGAz//Yy9gcYOVafeYZQNOZZCMEALWNeg5gw1AO+RUpxAWTM+KOLQuBv36lbzuhkI5aAIQJGKgE6ApfkCinQaQMOv73A7iDBgWCwL8Kdx2+8q/OO50AIKb/8gWI81vpfalVulOqlfqDBkEixLDohDTSWcIHIOeQT4RUdaYGDngmZUAHKJKaLiT2EMgC3X393BVxcaw77f9hcCmB+2lvbmsAB25Ea2J1Br7XYIDGyOnNigGzmbS19rJkgWYr39LWbj7C6Q95tBq3YQoxT7A0Rk4BVBkOzAZuejPpIloka56saXn/fq5jdW12u45o2x0OHadvtdlCC6iFYTXf+GXF2lSipNxUx3hDzehsUyzQJJ72P+Rh+OX3qYaDPKszyYlpnGy9FWC3E23KuVU+ZNIZtGret+y6EWU08sRgkJsOyy/asw/eZ3X2OuMhTp9xyZFzLcfhINrd3jYb3KQ0q7MQwjILtobpCtxGd3JtkynNUVZiQVzx6UVaKyfVHwOMRo9W4xmMaAyszkS09vxZzJzeBk4bf/Jl+kVWl3r+eexxaM5EGY95nLD5cXscCWarwnqOcJr3kcff+xq3QbOVB2DMXWa3VhLdVe9uRGtWmLYH5o7m3fZ4i71+f8IpR/UzTq98Yos7gemoLytTVqxIyVMq86Jlwn4BXSRLS5PxVG8QUkVBqYf6j/3++yef/PFHetBBydU1EybU15gwfptVIrVuW7lizVUpKg+qxNvEGWHiY6JLKTdOtL2JX8qoOCoxAcpXOlXqsFq4pVpkGfteFVwfVD97Ns4Fq1QJjYjFQhSoZjYVTsvhM0NdLVm1hE0qH4+JdojHxFYR4ljEt7Qdz1266dAg2WRmMTM5KIinxd3Cy+Ih8VEBkpuQ999/oyrlxVVavPmZWfUh1rMz7lDCY0Io5pdREd+WRjTNKTMD30FlornFGLHIrXveJ5vKm2aX2ryBCKpsvgKiK5PuzDhrqQ/NnMF7162JaD69yTX+4YUmr8ZuUXlKzepa+UhLRUTbvApcgvoPhVPx+6ebXUIyQsUW0WYkEYeKwOYRm+ZaLZbQfzUNCQ1xVQYmCBy1fLtrzeaSn352JsfBnUb5VPuVeskZKLpqREdMgiomMejPBaPhEaMjfyYlxviW8fNka97FtRYsK8B3/m6NbB5f5quM9a358nZ+W97DjyVs90B/Nyv56GJansi3y/PyCx+fz496dfmK8tIufmTA7R/IffwwzyF2+0vHTWOz1+9pLCpOykhPKiY/c896LLkNAE4AfRuEdLcDNZ8Bc1KU8iYEAAF2Fq77fKI0938xxwAAvrEGPwNf1w9iUEDhOk8OwWEepocgrJgJLqg43Y0YagEDDqVMgKQGzANTzTF1SHASZNUVAoA1UxChzkxDgETIMHvMAnCQmoUQoKA7C29MB11qGReQsCCYKUjQaqbBIg0yzEGzAHJ4m4VgUdrKIhVrL2z3moEh9GAK1JhxQ3ybpPhEtKEP06HHRXmBSEI8El1mk3je4++D0IQ+DGAWRjEZ00f80MOMm2sFZc+Uf3QxiXKjsTMRiAH0Qb0J9pMxE33o7duNeQiEcnWkFmHz9ceDxgQAAAA=);
44
font-weight: normal;
55
font-style: normal;
66
font-display: block;
@@ -31,6 +31,9 @@ i {
3131
.icon-comments:before {
3232
content: "\f086";
3333
}
34+
.icon-clipboard:before {
35+
content: "\f0ea";
36+
}
3437
.icon-lightbulb-o:before {
3538
content: "\f0eb";
3639
}

docs/source/css/main.css

+33
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,39 @@ table tr:last-child td {
168168
border-bottom: 0;
169169
}
170170

171+
div.highlight {
172+
position: relative;
173+
}
174+
175+
div.highlight .copy {
176+
background: var(--white);
177+
display: none;
178+
border-radius: var(--border-radius);
179+
border: 1px solid var(--border);
180+
cursor: pointer;
181+
font-size: 12px;
182+
padding: 5px;
183+
position: absolute;
184+
right: 5px;
185+
top: 5px;
186+
}
187+
188+
div.highlight .copy .copied-text {
189+
display: none;
190+
}
191+
192+
div.highlight .copy.copied .copied-text {
193+
display: inline;
194+
}
195+
196+
div.highlight .copy.copied .copy-text {
197+
display: none;
198+
}
199+
200+
div.highlight:hover .copy {
201+
display: block;
202+
}
203+
171204
.highlight .k {
172205
font-weight: bold;
173206
}

docs/source/js/main.js

+20-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
(function() {
22
"use strict";
33

4-
document.addEventListener('DOMContentLoaded', function() {
5-
document.querySelectorAll('.expand-menus a').forEach(function(button) {
6-
button.addEventListener('click', function(event) {
4+
document.addEventListener('DOMContentLoaded', () => {
5+
document.querySelectorAll('.expand-menus a').forEach((button) => {
6+
button.addEventListener('click', (event) => {
77
event.preventDefault();
88

99
let query = button.dataset.toggle;
@@ -15,5 +15,22 @@
1515
document.querySelector(query).classList.toggle('visible');
1616
});
1717
});
18+
19+
document.querySelectorAll('.highlight .copy').forEach((el) => {
20+
let timer = null;
21+
22+
el.addEventListener('click', (e) => {
23+
e.preventDefault();
24+
25+
if (timer) {
26+
clearTimeout(timer);
27+
timer = null;
28+
}
29+
30+
el.classList.add('copied');
31+
navigator.clipboard.writeText(el.previousSibling.textContent);
32+
timer = setTimeout(function() { el.classList.remove('copied'); }, 2000);
33+
});
34+
});
1835
});
1936
})();

docs/src/docs/filters.inko

+28
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,34 @@ impl Filter for AutoTableOfContents {
2323
}
2424
}
2525

26+
class AddCopyButton {
27+
fn static new -> AddCopyButton {
28+
AddCopyButton()
29+
}
30+
}
31+
32+
impl Filter for AddCopyButton {
33+
fn pub mut run(document: mut Document) {
34+
document.nodes.iter_mut.each(fn (n) {
35+
let el = match n {
36+
case Element(e) if e.name == 'div' -> {
37+
match e.attributes.opt('class') {
38+
case Some('highlight') -> e
39+
case _ -> return
40+
}
41+
}
42+
case _ -> return
43+
}
44+
45+
el.button.attr('class', 'copy').with(fn (btn) {
46+
btn.i.attr('class', 'icon-clipboard')
47+
btn.span.attr('class', 'copy-text').text(' Copy')
48+
btn.span.attr('class', 'copied-text').text(' Copied!')
49+
})
50+
})
51+
}
52+
}
53+
2654
# A filter that turns relative document links (e.g. `[](ivm)`) into the correct
2755
# URLs, optionally setting the link text if left out. This makes it easier to
2856
# link to different documents.

docs/src/docs/layouts.inko

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import builder.html
22
import builder.xml
33
import docs.config (Config)
4-
import docs.filters (AutoTableOfContents, RelativeLinks)
4+
import docs.filters (AddCopyButton, AutoTableOfContents, RelativeLinks)
55
import docs.menu (Item, Menu)
66
import docs.url (link_from)
77
import markdown.html (Filter, TableOfContents)
@@ -15,6 +15,7 @@ fn filters(menu: ref Menu, page: ref Page) -> Array[Filter] {
1515
SyntaxHighlight.new as Filter,
1616
Admonitions.new as Filter,
1717
RelativeLinks(menu: menu, page: page) as Filter,
18+
AddCopyButton.new as Filter,
1819
AutoTableOfContents() as Filter, # This filter must come last
1920
]
2021
}

0 commit comments

Comments
 (0)