mirror of
https://github.com/snachodog/just-the-docs.git
synced 2025-04-10 14:01:22 -06:00
Add copy code button to code snippets (#945)
Hello everyone, this is my implementation for the copy button on the snippet (requested in #924) The implementation is made 100% javascript as with or without a jekyll template modification you still have to execute some javascript code, and I consider it the best choice. the button only appears if the mouse is over it, to allow the entire line to be read the important CSS changes were made to make the copy button work even in the long code situation:  to avoid this:  Co-authored-by: Matt Wang <matt@matthewwang.me>
This commit is contained in:
parent
56bda83528
commit
ce3f34bbc7
@ -73,6 +73,9 @@ search:
|
||||
# Supports true or false (default)
|
||||
button: false
|
||||
|
||||
# For copy button on code
|
||||
enable_copy_code_button: true
|
||||
|
||||
# To disable support for mermaid diagrams (https://mermaid-js.github.io/mermaid/),
|
||||
# comment out the `mermaid` and `version` keys below
|
||||
# By default, consuming the theme as a gem leaves mermaid disabled; it is opt-in
|
||||
|
15
_includes/icons/code_copy.html
Normal file
15
_includes/icons/code_copy.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!-- Feather. MIT License: https://github.com/twbs/icons/blob/main/LICENSE.md -->
|
||||
<symbol id="svg-copy" viewBox="0 0 16 16">
|
||||
<title>Copy</title>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard" viewBox="0 0 16 16">
|
||||
<path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/>
|
||||
<path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/>
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-copied" viewBox="0 0 16 16">
|
||||
<title>Copied</title>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard-check-fill" viewBox="0 0 16 16">
|
||||
<path d="M6.5 0A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3Zm3 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3Z"/>
|
||||
<path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1A2.5 2.5 0 0 1 9.5 5h-3A2.5 2.5 0 0 1 4 2.5v-1Zm6.854 7.354-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 0 1 .708-.708L7.5 10.793l2.646-2.647a.5.5 0 0 1 .708.708Z"/>
|
||||
</svg>
|
||||
</symbol>
|
@ -40,6 +40,7 @@ layout: table_wrappers
|
||||
</svg>
|
||||
</symbol>
|
||||
{% include icons/external_link.html %}
|
||||
{% include icons/code_copy.html %}
|
||||
</svg>
|
||||
|
||||
<div class="side-bar">
|
||||
|
108
_sass/code.scss
108
_sass/code.scss
@ -3,12 +3,15 @@
|
||||
|
||||
// {% raw %}
|
||||
|
||||
code {
|
||||
padding: 0.2em 0.15em;
|
||||
font-weight: 400;
|
||||
background-color: $code-background-color;
|
||||
border: $border $border-color;
|
||||
border-radius: $border-radius;
|
||||
// This instruction applies to all queues not within 'pre', avoiding 'code' generated by the highlight.
|
||||
:not(pre) {
|
||||
& > code {
|
||||
padding: 0.2em 0.15em;
|
||||
font-weight: 400;
|
||||
background-color: $code-background-color;
|
||||
border: $border $border-color;
|
||||
border-radius: $border-radius;
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid appearance of dark border around visited code links in Safari
|
||||
@ -47,18 +50,77 @@ a:visited code {
|
||||
// Kramdown line_numbers = true: fences have a wider gutter than with Liquid?
|
||||
|
||||
// ```[LANG]...```
|
||||
|
||||
// the code may appear with 3 different types:
|
||||
// container \ case: default case, code with line number, code with html rendering
|
||||
// top level: div.highlighter-rouge, div.listingblock > div.content, figure.highlight
|
||||
// second level: div.highlight, .table-wrapper, pre
|
||||
// third level: pre.highlight, td.code, absent
|
||||
// last level: code, pre, code (optionality)
|
||||
// highlighter level: span, span, span
|
||||
// the spacing are only in the second level for case 1, 3 and in the thirt level for case 2
|
||||
|
||||
// select top level container
|
||||
div.highlighter-rouge,
|
||||
div.listingblock > div.content {
|
||||
padding: $sp-3;
|
||||
div.listingblock > div.content,
|
||||
figure.highlight {
|
||||
margin-top: 0;
|
||||
margin-bottom: $sp-3;
|
||||
overflow-x: auto;
|
||||
background-color: $code-background-color;
|
||||
border-radius: $border-radius;
|
||||
box-shadow: none;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
|
||||
// copy button (or other button)
|
||||
// the button appear only when there is a hover on the code or focus on button
|
||||
> button {
|
||||
width: $sp-3;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
border: $sp-3 solid $code-background-color;
|
||||
background-color: $code-background-color;
|
||||
color: $body-text-color;
|
||||
box-sizing: content-box;
|
||||
|
||||
svg {
|
||||
fill: $body-text-color;
|
||||
}
|
||||
|
||||
&:active {
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// the button can be seen by doing a simple hover in the code, there is no need to go over the location of the button
|
||||
&:hover {
|
||||
> button {
|
||||
cursor: copy;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setting the spacing and scrollbar on the second level for the first case
|
||||
// remove all space on the second and thirt level
|
||||
div.highlighter-rouge,
|
||||
div.listingblock {
|
||||
div.highlight {
|
||||
overflow-x: auto;
|
||||
padding: $sp-3;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
div.highlight,
|
||||
pre.highlight,
|
||||
code {
|
||||
padding: 0;
|
||||
@ -69,19 +131,15 @@ div.listingblock > div.content {
|
||||
|
||||
// {% highlight LANG %}...{% endhighlight %},
|
||||
// {% highlight LANG linenos %}...{% endhighlight %}:
|
||||
figure.highlight {
|
||||
padding: $sp-3;
|
||||
margin-top: 0;
|
||||
margin-bottom: $sp-3;
|
||||
overflow-x: auto;
|
||||
background-color: $code-background-color;
|
||||
border-radius: $border-radius;
|
||||
box-shadow: none;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
// setting the spacing and scrollbar on the second level for the thirt case
|
||||
// the css rule are apply only to the last code enviroment
|
||||
// setting the scroolbar
|
||||
figure.highlight {
|
||||
pre,
|
||||
code {
|
||||
padding: 0;
|
||||
:not(pre) > code {
|
||||
overflow-x: auto;
|
||||
padding: $sp-3;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
@ -89,6 +147,8 @@ figure.highlight {
|
||||
|
||||
// ```[LANG]...```, kramdown line_numbers = true,
|
||||
// {% highlight LANG linenos %}...{% endhighlight %}:
|
||||
|
||||
// setting the spacing and scrollbar on the thirt level for the second case
|
||||
.highlight .table-wrapper {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
@ -108,6 +168,7 @@ figure.highlight {
|
||||
td.gl {
|
||||
width: 1em;
|
||||
padding-right: $sp-3;
|
||||
padding-left: $sp-3;
|
||||
}
|
||||
|
||||
pre {
|
||||
@ -116,10 +177,7 @@ figure.highlight {
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Code examples (rendered)
|
||||
//
|
||||
|
||||
// Code examples: html render of a code
|
||||
.code-example,
|
||||
.listingblock > .title {
|
||||
padding: $sp-3;
|
||||
|
@ -479,6 +479,47 @@ jtd.onReady(function(){
|
||||
scrollNav();
|
||||
});
|
||||
|
||||
// Copy button on code
|
||||
|
||||
|
||||
{%- if site.enable_copy_code_button != false %}
|
||||
|
||||
jtd.onReady(function(){
|
||||
|
||||
var codeBlocks = document.querySelectorAll('div.highlighter-rouge, div.listingblock, figure.highlight');
|
||||
|
||||
var svgCopied = '<svg viewBox="0 0 24 24" class="copy-icon"><use xlink:href="#svg-copied"></use></svg>';
|
||||
var svgCopy = '<svg viewBox="0 0 24 24" class="copy-icon"><use xlink:href="#svg-copy"></use></svg>';
|
||||
|
||||
codeBlocks.forEach(codeBlock => {
|
||||
var copyButton = document.createElement('button');
|
||||
var timeout = null;
|
||||
copyButton.type = 'button';
|
||||
copyButton.ariaLabel = 'Copy code to clipboard';
|
||||
copyButton.innerHTML = svgCopy;
|
||||
codeBlock.append(copyButton);
|
||||
|
||||
copyButton.addEventListener('click', function () {
|
||||
if(timeout === null) {
|
||||
var code = codeBlock.querySelector('code').innerText.trim();
|
||||
window.navigator.clipboard.writeText(code);
|
||||
|
||||
copyButton.innerHTML = svgCopied;
|
||||
|
||||
var timeoutSetting = 4000;
|
||||
|
||||
timeout = setTimeout(function () {
|
||||
copyButton.innerHTML = svgCopy;
|
||||
timeout = null;
|
||||
}, timeoutSetting);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
{%- endif %}
|
||||
|
||||
})(window.jtd = window.jtd || {});
|
||||
|
||||
{% include js/custom.js %}
|
||||
|
@ -143,3 +143,14 @@ graph TD;
|
||||
```
|
||||
|
||||
*Note: for demonstration purposes, we've enabled mermaid on this site. It is still disabled by default, and users need to opt-in to use it.*
|
||||
|
||||
## Copy button
|
||||
|
||||
The copy button for code blocks can be enabled or disabled via the `enable_copy_code_button` key in `_config.yml`. By default, the value of this key is `false`; users need to opt-in.
|
||||
|
||||
```yaml
|
||||
# For copy button on code
|
||||
enable_copy_code_button: true
|
||||
```
|
||||
|
||||
Note that this feature requires JavaScript; if JavaScript is disabled in the browser, this feature will not work.
|
Loading…
x
Reference in New Issue
Block a user