From ac21c2619aeb25f943ea87d1f42189669552d08e Mon Sep 17 00:00:00 2001 From: Oashe02 Date: Sat, 15 Nov 2025 23:52:34 +0530 Subject: [PATCH 1/5] feat: Copy/Clickboard button in code snippets --- layouts/_default/baseof.html | 4 ++++ static/css/copy-code.css | 43 ++++++++++++++++++++++++++++++++++++ static/js/copy-code.js | 36 ++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 static/css/copy-code.css create mode 100644 static/js/copy-code.js diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index 429e9a6..d9f6653 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -45,6 +45,10 @@

Helmet.js

{{ block "main" . }}{{ end }} + + + + diff --git a/static/css/copy-code.css b/static/css/copy-code.css new file mode 100644 index 0000000..d52463c --- /dev/null +++ b/static/css/copy-code.css @@ -0,0 +1,43 @@ +pre { + position: relative !important; + padding-top: 2.5em; + overflow-x: auto; +} + +.copy-code-button { + position: absolute !important; + top: 8px; + right: 8px; + padding: 6px 10px; + font-size: 14px; + border-radius: 6px; + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(4px); + color: #fff; + border: 1px solid rgba(255, 255, 255, 0.2); + cursor: pointer; + z-index: 100; + transition: all 0.2s ease; + margin: 0; + pointer-events: auto; +} + +.copy-code-button:hover { + background: rgba(255, 255, 255, 0.25); + border-color: rgba(255, 255, 255, 0.3); + transform: scale(1.05); +} + +.copy-code-button:active { + transform: scale(0.95); +} + +pre code { + display: block; + padding: 1em; + padding-top: 0; + margin: 0; + background: none; + position: static !important; + overflow-x: auto; +} \ No newline at end of file diff --git a/static/js/copy-code.js b/static/js/copy-code.js new file mode 100644 index 0000000..cef3c3b --- /dev/null +++ b/static/js/copy-code.js @@ -0,0 +1,36 @@ +(function () { + document.addEventListener("DOMContentLoaded", () => { + const blocks = document.querySelectorAll( + "pre > code.language-js, pre > code.language-javascript" + ); + + blocks.forEach((code) => { + const pre = code.parentElement; + pre.style.position = "relative"; + const btn = document.createElement("button"); + btn.className = "copy-code-button"; + btn.innerHTML = + 'content_copy'; + pre.appendChild(btn); + btn.addEventListener("click", async () => { + try { + await navigator.clipboard.writeText(code.innerText.trim()); + btn.innerHTML = + 'check'; + setTimeout(() => { + btn.innerHTML = + 'content_copy'; + }, 800); + } catch (err) { + btn.innerHTML = + 'error'; + setTimeout(() => { + btn.innerHTML = + 'content_copy'; + }, 800); + } + }); + }); + }); +})(); + From 47a381eb69bbb34da9d8a7f8f4e7dcc1f6038099 Mon Sep 17 00:00:00 2001 From: Oashe02 Date: Mon, 17 Nov 2025 10:28:28 +0530 Subject: [PATCH 2/5] added Material Symbols icon font link --- layouts/_default/baseof.html | 5 +++++ static/css/copy-code.css | 34 ++++++++++++++++++---------------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index d9f6653..45308b7 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -24,6 +24,11 @@ + + diff --git a/static/css/copy-code.css b/static/css/copy-code.css index d52463c..52749a6 100644 --- a/static/css/copy-code.css +++ b/static/css/copy-code.css @@ -1,35 +1,37 @@ pre { position: relative !important; - padding-top: 2.5em; + padding-top: 2.8em; overflow-x: auto; } .copy-code-button { position: absolute !important; - top: 8px; - right: 8px; - padding: 6px 10px; - font-size: 14px; - border-radius: 6px; - background: rgba(255, 255, 255, 0.1); - backdrop-filter: blur(4px); + top: 12px; + right: 12px; + width: 16px; + height: 16px; + padding: 0; + display: flex; + align-items: center; + justify-content: center; + font-size: 10px; + line-height: 1; + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.15); + border-radius: 4px; color: #fff; - border: 1px solid rgba(255, 255, 255, 0.2); cursor: pointer; - z-index: 100; - transition: all 0.2s ease; - margin: 0; - pointer-events: auto; + z-index: 300; + transition: all 0.15s ease; } .copy-code-button:hover { - background: rgba(255, 255, 255, 0.25); - border-color: rgba(255, 255, 255, 0.3); + background: rgba(255, 255, 255, 0.18); transform: scale(1.05); } .copy-code-button:active { - transform: scale(0.95); + transform: scale(0.85); } pre code { From 50556e2e6e6259a946bfd27cdbc78c4914ad6a65 Mon Sep 17 00:00:00 2001 From: Oashe02 Date: Mon, 17 Nov 2025 11:55:15 +0530 Subject: [PATCH 3/5] added css in global file --- assets/sass/global.scss | 44 ++++++++++++++++++++++++++++++++-------- static/css/copy-code.css | 2 +- static/js/copy-code.js | 6 ++++-- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/assets/sass/global.scss b/assets/sass/global.scss index c0dfe14..87dbc4e 100644 --- a/assets/sass/global.scss +++ b/assets/sass/global.scss @@ -5,12 +5,7 @@ body { color: var(--text-color); background: var(--background-color); - font-family: - "Helvetica Neue", - "Segoe UI", - "Noto Sans", - Helvetica, - Arial, + font-family: "Helvetica Neue", "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif; font-size: 20px; line-height: 2em; @@ -22,18 +17,30 @@ a { color: var(--accent-color); } -a:hover, a:active { +a:hover, +a:active { text-decoration: underline; } -pre, code { +pre, +code { font-family: Monaco, "Ubuntu Mono", Inconsolata, Consolas, monospace; } pre { line-height: 1.4em; + + margin: 20px !important; // remove ALL outside spacing + padding: 0 !important; // remove ALL inside spacing +} + +pre > code { + margin: 0 !important; // remove internal margin + padding: 16px !important; // remove internal padding + display: block !important; } + strong { font-weight: bold; } @@ -58,3 +65,24 @@ em { transform: translateY(0%); } } + + +.copy-code-button { + position: absolute; + top: 6px; + right: 6px; + padding: 0; + font-size: 12px; + + background: transparent !important; + border: none !important; + box-shadow: none !important; + outline: none !important; + + cursor: pointer; +} + +.copy-code-button span { + font-size: 16px; + background: transparent !important; +} diff --git a/static/css/copy-code.css b/static/css/copy-code.css index 52749a6..7c5a475 100644 --- a/static/css/copy-code.css +++ b/static/css/copy-code.css @@ -1,6 +1,6 @@ pre { position: relative !important; - padding-top: 2.8em; + padding-top: 2em; overflow-x: auto; } diff --git a/static/js/copy-code.js b/static/js/copy-code.js index cef3c3b..231caac 100644 --- a/static/js/copy-code.js +++ b/static/js/copy-code.js @@ -7,11 +7,14 @@ blocks.forEach((code) => { const pre = code.parentElement; pre.style.position = "relative"; + const btn = document.createElement("button"); btn.className = "copy-code-button"; btn.innerHTML = 'content_copy'; + pre.appendChild(btn); + btn.addEventListener("click", async () => { try { await navigator.clipboard.writeText(code.innerText.trim()); @@ -32,5 +35,4 @@ }); }); }); -})(); - +})(); \ No newline at end of file From cda9f11fa62100f68b693a524402a8748aef827c Mon Sep 17 00:00:00 2001 From: Oashe02 Date: Mon, 17 Nov 2025 11:56:09 +0530 Subject: [PATCH 4/5] minor change --- assets/sass/global.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/sass/global.scss b/assets/sass/global.scss index 87dbc4e..b0db9df 100644 --- a/assets/sass/global.scss +++ b/assets/sass/global.scss @@ -30,7 +30,7 @@ code { pre { line-height: 1.4em; - margin: 20px !important; // remove ALL outside spacing + margin: 20px 0 !important; // remove ALL outside spacing padding: 0 !important; // remove ALL inside spacing } From 7fb48b75a1f31e6d85d1fc25c18757beccd6b4c1 Mon Sep 17 00:00:00 2001 From: Oashe02 Date: Sat, 22 Nov 2025 10:18:09 +0530 Subject: [PATCH 5/5] copy button fixed --- assets/sass/content.scss | 50 +++++++++++++++- assets/sass/global.scss | 47 ++++----------- layouts/_default/baseof.html | 5 -- static/css/copy-code.css | 45 --------------- static/js/copy-code.js | 107 +++++++++++++++++++++++------------ 5 files changed, 130 insertions(+), 124 deletions(-) delete mode 100644 static/css/copy-code.css diff --git a/assets/sass/content.scss b/assets/sass/content.scss index 1a03fc8..8a93c03 100644 --- a/assets/sass/content.scss +++ b/assets/sass/content.scss @@ -48,6 +48,54 @@ pre { padding: 1rem; border-radius: 5px; overflow-x: auto; + position: relative; +} + +.code-block-wrapper { + position: relative; + margin-bottom: 1.5rem; +} + +.copy-code-button { + position: absolute; + top: 8px; + right: 6px; + + width: 20px ; + height: 20px; + + padding: 0; + margin: 0; + + background: transparent; + border: none; + + display: flex; + align-items: center; + justify-content: center; + + cursor: pointer; + color: currentColor; + + z-index: 20; +} + +.copy-code-button svg { + width: 14px ; + height: 14px ; + display: block; +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; } details { @@ -58,5 +106,5 @@ details { } details[open] { - border-color: 1px solid var(--text-color); + border-color: var(--text-color); } diff --git a/assets/sass/global.scss b/assets/sass/global.scss index b0db9df..96c5097 100644 --- a/assets/sass/global.scss +++ b/assets/sass/global.scss @@ -5,7 +5,12 @@ body { color: var(--text-color); background: var(--background-color); - font-family: "Helvetica Neue", "Segoe UI", "Noto Sans", Helvetica, Arial, + font-family: + "Helvetica Neue", + "Segoe UI", + "Noto Sans", + Helvetica, + Arial, sans-serif; font-size: 20px; line-height: 2em; @@ -17,30 +22,19 @@ a { color: var(--accent-color); } -a:hover, -a:active { +a:hover, a:active { text-decoration: underline; } -pre, -code { +pre, code { font-family: Monaco, "Ubuntu Mono", Inconsolata, Consolas, monospace; } + pre { line-height: 1.4em; - - margin: 20px 0 !important; // remove ALL outside spacing - padding: 0 !important; // remove ALL inside spacing -} - -pre > code { - margin: 0 !important; // remove internal margin - padding: 16px !important; // remove internal padding - display: block !important; } - strong { font-weight: bold; } @@ -64,25 +58,4 @@ em { &:focus { transform: translateY(0%); } -} - - -.copy-code-button { - position: absolute; - top: 6px; - right: 6px; - padding: 0; - font-size: 12px; - - background: transparent !important; - border: none !important; - box-shadow: none !important; - outline: none !important; - - cursor: pointer; -} - -.copy-code-button span { - font-size: 16px; - background: transparent !important; -} +} \ No newline at end of file diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index 45308b7..36b1a1f 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -24,10 +24,6 @@ - @@ -50,7 +46,6 @@

Helmet.js

{{ block "main" . }}{{ end }} - diff --git a/static/css/copy-code.css b/static/css/copy-code.css deleted file mode 100644 index 7c5a475..0000000 --- a/static/css/copy-code.css +++ /dev/null @@ -1,45 +0,0 @@ -pre { - position: relative !important; - padding-top: 2em; - overflow-x: auto; -} - -.copy-code-button { - position: absolute !important; - top: 12px; - right: 12px; - width: 16px; - height: 16px; - padding: 0; - display: flex; - align-items: center; - justify-content: center; - font-size: 10px; - line-height: 1; - background: rgba(255, 255, 255, 0.06); - border: 1px solid rgba(255, 255, 255, 0.15); - border-radius: 4px; - color: #fff; - cursor: pointer; - z-index: 300; - transition: all 0.15s ease; -} - -.copy-code-button:hover { - background: rgba(255, 255, 255, 0.18); - transform: scale(1.05); -} - -.copy-code-button:active { - transform: scale(0.85); -} - -pre code { - display: block; - padding: 1em; - padding-top: 0; - margin: 0; - background: none; - position: static !important; - overflow-x: auto; -} \ No newline at end of file diff --git a/static/js/copy-code.js b/static/js/copy-code.js index 231caac..5e0b0d4 100644 --- a/static/js/copy-code.js +++ b/static/js/copy-code.js @@ -1,38 +1,73 @@ -(function () { - document.addEventListener("DOMContentLoaded", () => { - const blocks = document.querySelectorAll( - "pre > code.language-js, pre > code.language-javascript" - ); - - blocks.forEach((code) => { - const pre = code.parentElement; - pre.style.position = "relative"; - - const btn = document.createElement("button"); - btn.className = "copy-code-button"; - btn.innerHTML = - 'content_copy'; - - pre.appendChild(btn); - - btn.addEventListener("click", async () => { - try { - await navigator.clipboard.writeText(code.innerText.trim()); - btn.innerHTML = - 'check'; - setTimeout(() => { - btn.innerHTML = - 'content_copy'; - }, 800); - } catch (err) { - btn.innerHTML = - 'error'; - setTimeout(() => { - btn.innerHTML = - 'content_copy'; - }, 800); - } - }); +document.addEventListener("DOMContentLoaded", () => { + const blocks = document.querySelectorAll( + "pre > code.language-js, pre > code.language-javascript" + ); + + const COPY_SVG = ` + +`; + + const CHECK_SVG = ` + +`; + + function setButtonState(btn, iconHTML, srText) { + btn.innerHTML = ` + ${iconHTML} + ${srText} + `; + btn.setAttribute("aria-label", srText); + } + + blocks.forEach((code) => { + const pre = code.parentElement; + + let wrapper = pre.parentElement; + if (!wrapper.classList.contains("code-block-wrapper")) { + wrapper = document.createElement("div"); + wrapper.className = "code-block-wrapper"; + pre.replaceWith(wrapper); + wrapper.appendChild(pre); + } + + const btn = document.createElement("button"); + btn.className = "copy-code-button"; + setButtonState(btn, COPY_SVG, "Copy code"); + + wrapper.appendChild(btn); + + let resetTimeout = null; + let isCooling = false; + + btn.addEventListener("click", async () => { + if (isCooling) return; + isCooling = true; + + try { + await navigator.clipboard.writeText(code.innerText.trim()); + setButtonState(btn, CHECK_SVG, "Copied"); + } catch { + setButtonState(btn, COPY_SVG, "Copy code"); + } + + if (resetTimeout) clearTimeout(resetTimeout); + + resetTimeout = setTimeout(() => { + setButtonState(btn, COPY_SVG, "Copy code"); + isCooling = false; + resetTimeout = null; + }, 1000); }); }); -})(); \ No newline at end of file +});