feat: copy code to clipboard on blog posts
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
parent
d28d33052f
commit
703556d238
6 changed files with 99 additions and 0 deletions
|
@ -85,3 +85,17 @@ $std-trans: 0.3s;
|
||||||
margin: 5px !important;
|
margin: 5px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.copy-code {
|
||||||
|
margin: auto;
|
||||||
|
margin-top: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog__content pre {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog__content code {
|
||||||
|
flex: auto;
|
||||||
|
}
|
||||||
|
|
1
static/icons/check.svg
Normal file
1
static/icons/check.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#39d353" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check"><polyline points="20 6 9 17 4 12"></polyline></svg>
|
After Width: | Height: | Size: 257 B |
1
static/icons/clipboard.svg
Normal file
1
static/icons/clipboard.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#768390" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-clipboard"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg>
|
After Width: | Height: | Size: 366 B |
79
static/js/copy.js
Normal file
79
static/js/copy.js
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const check_dataset = (id, property) => {
|
||||||
|
let elem = document.getElementById(id);
|
||||||
|
if (elem === undefined || elem == null) {
|
||||||
|
console.warn(`${id} not found`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!elem.dataset.hasOwnProperty(property)) {
|
||||||
|
console.warn(`${id} component doesn't have ${property} dataset attribute`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return elem;
|
||||||
|
};
|
||||||
|
|
||||||
|
const init_clipboard = () => {
|
||||||
|
const CHECK_COMPONENT = check_dataset("check-icon", "check");
|
||||||
|
if (CHECK_COMPONENT == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const CHECK_ICON = CHECK_COMPONENT.dataset.check;
|
||||||
|
|
||||||
|
const CLIPBOARD_COMPONET = check_dataset("clipboard-icon", "clipboard");
|
||||||
|
if (CLIPBOARD_COMPONET == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const CLIPBOARD_ICON = CLIPBOARD_COMPONET.dataset.clipboard;
|
||||||
|
|
||||||
|
const copy_code = async (event) => {
|
||||||
|
const switch_clipboard_icon = async (event) => {
|
||||||
|
event.target.src = CHECK_ICON;
|
||||||
|
setTimeout(() => {
|
||||||
|
event.target.src = CLIPBOARD_ICON;
|
||||||
|
}, 1200);
|
||||||
|
};
|
||||||
|
|
||||||
|
let elem = event.target;
|
||||||
|
let codes = Array.from(elem.parentElement.getElementsByTagName("span"));
|
||||||
|
let content = "";
|
||||||
|
codes.forEach((span) => {
|
||||||
|
content = `${content} ${span.innerText}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
await navigator.clipboard.writeText(content);
|
||||||
|
await switch_clipboard_icon(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
const new_clipboard = () => {
|
||||||
|
let clipboard = document.createElement("img");
|
||||||
|
clipboard.src = CLIPBOARD_ICON;
|
||||||
|
clipboard.classList = ["copy-code"];
|
||||||
|
clipboard.addEventListener("click", copy_code);
|
||||||
|
return clipboard;
|
||||||
|
};
|
||||||
|
|
||||||
|
document.querySelectorAll("code").forEach((code) => {
|
||||||
|
if (code.parentElement.tagName == "PRE") {
|
||||||
|
code.parentElement.appendChild(new_clipboard());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
init_clipboard();
|
|
@ -16,6 +16,7 @@
|
||||||
href="{{ get_url(path='/mobile.css') }}"
|
href="{{ get_url(path='/mobile.css') }}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
<meta name="referrer" content="no-referrer-when-downgrade" />
|
<meta name="referrer" content="no-referrer-when-downgrade" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
|
@ -50,6 +51,8 @@
|
||||||
<!-- End Matomo Code -->
|
<!-- End Matomo Code -->
|
||||||
</head>
|
</head>
|
||||||
<body class="base">
|
<body class="base">
|
||||||
|
<div id="check-icon" data-check="{{ get_url(path='/icons/check.svg', cachebust=true) }}"></div>
|
||||||
|
<div id="clipboard-icon" data-clipboard="{{ get_url(path='/icons/clipboard.svg', cachebust=true) }}"></div>
|
||||||
<header>{% include "nav.html" %}</header>
|
<header>{% include "nav.html" %}</header>
|
||||||
<!-- See ../sass/main.scss. Required for pushing footer to the very
|
<!-- See ../sass/main.scss. Required for pushing footer to the very
|
||||||
bottom of the page -->
|
bottom of the page -->
|
||||||
|
|
|
@ -19,4 +19,5 @@ endblock meta %} {% block content %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src="{{ get_url(path='/js/copy.js', cachebust=true) }}"></script>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
Loading…
Reference in a new issue