mirror of
https://github.com/thegeeklab/hugo-geekblog.git
synced 2024-11-21 12:40:39 +00:00
feat: add button to copy code blocks (#115)
This commit is contained in:
parent
26a710b53c
commit
c59f179d0b
@ -54,6 +54,8 @@ This method can be used to include source code files and keep them automatically
|
||||
{{</* include file="config.yaml" language="yaml" options="linenos=table,hl_lines=5-6,linenostart=100" */>}}
|
||||
```
|
||||
|
||||
**Code Include:**
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- spellchecker-disable -->
|
||||
{{< include file="config.yaml" language="yaml" options="linenos=table,hl_lines=5-6,linenostart=100">}}
|
||||
@ -77,9 +79,8 @@ HTML content will be filtered by the `safeHTML` filter and added to the rendered
|
||||
In some situations, it can be helpful to include Markdown files that also contain shortcodes. While the [default method](#markdown-file-default) works fine to render plain Markdown, shortcodes are not parsed. The only way to get this to work is to use Hugo pages. There are several ways to structure these include pages, so whatever you do, keep in mind that Hugo needs to be able to render and serve these files as regular pages! How it works:
|
||||
|
||||
1. First you need to create a directory **within** your content directory. For this example site `_includes` is used.
|
||||
2. To prevent the theme from embedding the page in the navigation, create a file `_includes/_index.md` and add `GeekdocHidden: true` to the front matter.
|
||||
3. Place your Markdown files within the `_includes` folder e.g. `/_includes/include-page.md`. Make sure to name it `*.md`.
|
||||
4. Include the page using `{{</* include file="/_includes/include-page.md" */>}}`.
|
||||
2. Place your Markdown files within the `_includes` folder e.g. `/_includes/include-page.md`. Make sure to name it `*.md`.
|
||||
3. Include the page using `{{</* include file="/_includes/include-page.md" */>}}`.
|
||||
|
||||
Resulting structure should look like this:
|
||||
|
||||
|
@ -16,7 +16,7 @@ There are several ways to add code blocks. Most of them work out of the box, onl
|
||||
|
||||
To display an inline shortcode use single quotes:
|
||||
|
||||
```plain
|
||||
```Plain
|
||||
`some code`
|
||||
```
|
||||
|
||||
@ -26,7 +26,7 @@ To display an inline shortcode use single quotes:
|
||||
|
||||
Code blocks can be uses without language specification:
|
||||
|
||||
````markdown
|
||||
````Markdown
|
||||
```Plain
|
||||
some code
|
||||
```
|
||||
@ -40,7 +40,7 @@ some code
|
||||
|
||||
... or if you need language specific syntax highlighting:
|
||||
|
||||
````markdown
|
||||
````Markdown
|
||||
```Shell
|
||||
# some code
|
||||
echo "Hello world"
|
||||
@ -80,7 +80,7 @@ pygmentsCodeFences: true
|
||||
You can use it like every other shortcode:
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```markdown
|
||||
```Markdown
|
||||
{{</* highlight Shell "linenos=table" */>}}
|
||||
# some code
|
||||
echo "Hello World"
|
||||
|
@ -2,3 +2,5 @@
|
||||
<script defer src="{{ index .Site.Data.assets "js/clipboard.min.js" | relURL }}"></script>
|
||||
<script defer src="{{ index .Site.Data.assets "js/clipboard-loader.min.js" | relURL }}"></script>
|
||||
{{ end }}
|
||||
|
||||
<script defer src="{{ index .Site.Data.assets "js/copycode.min.js" | relURL }}"></script>
|
||||
|
@ -43,7 +43,7 @@
|
||||
</section>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ if (default true .Site.Params.GeekdocBackToTop) }}
|
||||
{{ if (default true .Site.Params.GeekblogBackToTop) }}
|
||||
<div class="flex flex-25 justify-end">
|
||||
<span class="gblog-footer__item text-right">
|
||||
<a class="gblog-footer__link fake-link" href="#" aria-label="Back to top">
|
||||
|
@ -5,7 +5,7 @@
|
||||
<a class="gblog-header__link" rel="me" href="{{ .Site.BaseURL }}">
|
||||
<span class="gblog-brand flex align-center justify-center">
|
||||
<img class="gblog-brand__img" src="{{ (default "brand.svg" .Site.Params.logo) | relURL }}" alt="">
|
||||
<span class="gdoc-brand__title">{{ .Site.Title }}</span>
|
||||
<span class="gblog-brand__title">{{ .Site.Title }}</span>
|
||||
</span>
|
||||
{{ with .Site.Params.subtitle }}
|
||||
<span class="gblog-brand__subtitle flex align-center justify-center">{{ . }}</span>
|
||||
|
@ -4,7 +4,7 @@
|
||||
{{ $language := .Get "language" }}
|
||||
{{ $options :=.Get "options" }}
|
||||
|
||||
<div class="gdoc-include">
|
||||
<div class="gblog-include">
|
||||
{{- if (.Get "language") -}}
|
||||
{{- highlight ($file | readFile) $language (default "linenos=table" $options) -}}
|
||||
{{- else if eq $type "html" -}}
|
||||
|
1
src/iconfont/uEA21-check.svg
Normal file
1
src/iconfont/uEA21-check.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="-7.27 -7.27 42.55 42.55"><path d="M8.885 20.197L25.759 3.323l2.24 2.24L8.885 24.677 0 15.792l2.24-2.24z"/></svg>
|
After Width: | Height: | Size: 184 B |
1
src/iconfont/uEA22-copy.svg
Normal file
1
src/iconfont/uEA22-copy.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="-7.27 -7.27 42.55 42.55"><path d="M23.502 25.438V7.626H9.562v17.812h13.94zm0-20.315q1.013 0 1.787.745t.774 1.757v17.812q0 1.013-.774 1.787t-1.787.774H9.562q-1.013 0-1.787-.774t-.774-1.787V7.625q0-1.013.774-1.757t1.787-.745h13.94zM19.689 0v2.562H4.438v17.812H1.936V2.562q0-1.013.745-1.787T4.438.001h15.251z"/></svg>
|
After Width: | Height: | Size: 386 B |
5
src/icons/check.svg
Normal file
5
src/icons/check.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 28 28">
|
||||
<title>check</title>
|
||||
<path d="M8.885 20.197l16.874-16.874 2.24 2.24-19.114 19.114-8.885-8.885 2.24-2.24z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 252 B |
5
src/icons/copy.svg
Normal file
5
src/icons/copy.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 28 28">
|
||||
<title>copy</title>
|
||||
<path d="M23.502 25.438v-17.812h-13.94v17.812h13.94zM23.502 5.123q1.013 0 1.787 0.745t0.774 1.757v17.812q0 1.013-0.774 1.787t-1.787 0.774h-13.94q-1.013 0-1.787-0.774t-0.774-1.787v-17.812q0-1.013 0.774-1.757t1.787-0.745h13.94zM19.689 0v2.562h-15.251v17.812h-2.502v-17.812q0-1.013 0.745-1.787t1.757-0.774h15.251z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 478 B |
@ -1,3 +1,21 @@
|
||||
document.addEventListener("DOMContentLoaded", function (event) {
|
||||
var clipboard = new ClipboardJS(".clip");
|
||||
|
||||
clipboard.on("success", function (e) {
|
||||
const trigger = e.trigger;
|
||||
|
||||
if (trigger.hasAttribute("data-copy-feedback")) {
|
||||
trigger.classList.add("gblog-post__codecopy--success");
|
||||
trigger.querySelector(".icon.copy").classList.add("hidden");
|
||||
trigger.querySelector(".icon.check").classList.remove("hidden");
|
||||
|
||||
setTimeout(function () {
|
||||
trigger.classList.remove("gblog-post__codecopy--success");
|
||||
trigger.querySelector(".icon.copy").classList.remove("hidden");
|
||||
trigger.querySelector(".icon.check").classList.add("hidden");
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
e.clearSelection();
|
||||
});
|
||||
});
|
||||
|
34
src/js/copycode.js
Normal file
34
src/js/copycode.js
Normal file
@ -0,0 +1,34 @@
|
||||
function createCopyButton(highlightDiv) {
|
||||
const button = document.createElement("span");
|
||||
|
||||
if (highlightDiv.querySelector(".lntable")) {
|
||||
selector = ".lntable .lntd:last-child pre > code";
|
||||
} else {
|
||||
selector = "pre > code";
|
||||
}
|
||||
|
||||
const codeToCopy = highlightDiv.querySelector(selector).innerText.trim();
|
||||
|
||||
button.classList.add(
|
||||
"flex",
|
||||
"align-center",
|
||||
"justify-center",
|
||||
"clip",
|
||||
"gblog-post__codecopy"
|
||||
);
|
||||
button.type = "button";
|
||||
button.innerHTML =
|
||||
'<svg class="icon copy"><use xlink:href="#gblog_copy"></use></svg>' +
|
||||
'<svg class="icon check hidden"><use xlink:href="#gblog_check"></use></svg>';
|
||||
button.setAttribute("data-clipboard-text", codeToCopy);
|
||||
button.setAttribute("data-copy-feedback", "Copied!");
|
||||
button.setAttribute("role", "button");
|
||||
button.setAttribute("aria-label", "Copy");
|
||||
|
||||
highlightDiv.classList.add("gblog-post__codecontainer");
|
||||
highlightDiv.insertBefore(button, highlightDiv.firstChild);
|
||||
}
|
||||
|
||||
document
|
||||
.querySelectorAll(".highlight")
|
||||
.forEach((highlightDiv) => createCopyButton(highlightDiv));
|
@ -441,6 +441,46 @@ img {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
&__codecontainer {
|
||||
position: relative;
|
||||
|
||||
&:hover > .gblog-post__codecopy {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
&__codecopy {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
|
||||
border: $border-2 solid var(--code-copy-border-color);
|
||||
border-radius: $border-radius;
|
||||
background: var(--code-background);
|
||||
width: 2.2rem;
|
||||
height: 2.2rem;
|
||||
|
||||
.icon {
|
||||
top: 0;
|
||||
width: $font-size-20;
|
||||
height: $font-size-20;
|
||||
color: var(--code-copy-font-color);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&--success {
|
||||
border-color: var(--code-copy-success-color);
|
||||
|
||||
.icon {
|
||||
color: var(--code-copy-success-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gblog-footer {
|
||||
|
@ -66,7 +66,7 @@
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.svg-sprite {
|
||||
|
Loading…
Reference in New Issue
Block a user