From 8a18e31cedacff26ab7be6fc96c3b23544977d38 Mon Sep 17 00:00:00 2001 From: ondrej Date: Mon, 24 Oct 2022 00:40:58 +0200 Subject: [PATCH] Add copy button to code blocks (closes #18) --- assets/main.css | 1 + assets/main.js | 44 +++++++++++++++++++++++++++++++++++ assets/style.css | 14 +++++++++++ layouts/partials/scripts.html | 2 +- tailwind.config.js | 2 +- 5 files changed, 61 insertions(+), 2 deletions(-) diff --git a/assets/main.css b/assets/main.css index 56aa597..48a65d6 100644 --- a/assets/main.css +++ b/assets/main.css @@ -113,6 +113,7 @@ pre { border-radius: 0.25em; overflow-x: auto; padding: 1em; + position: relative; } .code-inline, diff --git a/assets/main.js b/assets/main.js index 7ac95df..c900c6b 100644 --- a/assets/main.js +++ b/assets/main.js @@ -5,3 +5,47 @@ window.Alpine = Alpine; Alpine.plugin(persist); Alpine.start(); + +/* Copy button component */ + +const copyIcon = ``; +const checkIcon = ``; +const defaultButtonLabel = `Zkopírovat text do schránky`; +const copiedButtonLabel = `Text zkopírován`; +const revertTimeout = 5_000; + +const accessibleLabel = (text) => `${text}`; + +const defaultButtonContent = copyIcon + accessibleLabel(defaultButtonLabel); +const copiedButtonContent = checkIcon + accessibleLabel(copiedButtonLabel); + +navigator.permissions + .query({ + name: "clipboard-read", + }) + .then((permission) => { + if (permission.state == "denied") { + return; + } + document + .querySelectorAll(".prose pre code, .code-block") + .forEach((codeBlock) => { + const button = document.createElement("button"); + button.innerHTML = defaultButtonContent; + button.className = "button absolute top-3 right-3 bg-white"; + + button.addEventListener("click", () => { + navigator.clipboard.writeText(codeBlock.innerHTML).then(() => { + button.innerHTML = copiedButtonContent; + setTimeout(() => { + button.innerHTML = defaultButtonContent; + }, revertTimeout); + }); + }); + + codeBlock.parentElement.insertBefore( + button, + codeBlock.nextElementSibling + ); + }); + }); diff --git a/assets/style.css b/assets/style.css index 8cfec9e..f9c4fae 100644 --- a/assets/style.css +++ b/assets/style.css @@ -630,6 +630,14 @@ video { right: 1.5rem; } +.top-3 { + top: 0.75rem; +} + +.right-3 { + right: 0.75rem; +} + .z-10 { z-index: 10; } @@ -784,6 +792,11 @@ video { background-color: rgb(243 244 246 / var(--tw-bg-opacity)); } +.bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} + .px-6 { padding-left: 1.5rem; padding-right: 1.5rem; @@ -966,6 +979,7 @@ pre { border-radius: 0.25em; overflow-x: auto; padding: 1em; + position: relative; } .code-inline, diff --git a/layouts/partials/scripts.html b/layouts/partials/scripts.html index 9f478d0..4f47824 100644 --- a/layouts/partials/scripts.html +++ b/layouts/partials/scripts.html @@ -1,2 +1,2 @@ -{{- $js := resources.Get "main.js" | js.Build | resources.Minify | fingerprint -}} +{{- $js := resources.Get "main.js" | js.Build | fingerprint -}} diff --git a/tailwind.config.js b/tailwind.config.js index 88743b3..0ff0656 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -2,7 +2,7 @@ const colors = require("tailwindcss/"); /** @type {import('tailwindcss').Config} */ module.exports = { - content: ["content/**/*.md", "layouts/**/*.html"], + content: ["content/**/*.md", "layouts/**/*.html", "assets/**/*.js"], theme: { fontFamily: { main: [