diff --git a/src/_posts/2023-02-19-copy-code-blocks.md b/src/_posts/2023-02-19-copy-code-blocks.md new file mode 100644 index 0000000..32a3261 --- /dev/null +++ b/src/_posts/2023-02-19-copy-code-blocks.md @@ -0,0 +1,157 @@ +--- +title: Copy Code Blocks +tags: [webdev, site] +category: [site, webdev] +date: 2023-02-19 +--- + +I've been reading [Bryce Wray's](https://www.brycewray.com) site for a little while. Its been interesting watching Bryce switch back and forth between [Hugo](https://github.com/brycewray/hugo_site) and [Eleventy / 11ty](https://github.com/brycewray/eleventy_site). Keeping both in sync feature wise. + +Just recently Bryce did a post about adding [Code for Copying Code](https://www.brycewray.com/posts/2023/02/code-copying-code-eleventy-edition/) in Eleventy. Essentially for any code block, it adds an icon (or you could switch it out for text) inside a code block that you can click and it will copy the code to your clipboard. + +On my site, the icon looks like this[^1]: + +![Screenshot of the top right corned of a code block. There is a small grey button with two overlapping squares shown](/assets/images/posts/copy-code-block.png) + +I am using Bryce's JavaScript virtually verbatim. The only difference is that I hook into the `load` event. Source from [copy-code-button.js](https://github.com/tarasis/tarasis.net/blob/main/src/assets/js/copy-code-button.js), with a minor change to the colour of the `svgCheck`. + +```js +/* +h/t to... +- https://www.brycewray.com/posts/2023/02/code-copying-code-eleventy-edition/ & Bryce's gitrepo +- https://github.com/brycewray/eleventy_site/blob/main/src/assets/js/copy-code-button.js +- https://www.dannyguo.com/blog/how-to-add-copy-to-clipboard-buttons-to-code-blocks-in-hugo/ +- https://aaronluna.dev/blog/add-copy-button-to-code-blocks-hugo-chroma/ +- https://simplernerd.com/hugo-add-copy-to-clipboard-button/ +- https://digitaldrummerj.me/hugo-add-copy-code-snippet-button/ +*/ + +const svgCopy = + ' Click to copy code'; +const svgCheck = + ' Copied!'; + +const addCopyButtons = (clipboard) => { + // 1. Look for pre > code elements in the DOM + document.querySelectorAll("pre > code").forEach((codeBlock) => { + // 2. Create a button that will trigger a copy operation + const button = document.createElement("button"); + button.className = "clipboard-button"; + button.type = "button"; + button.innerHTML = svgCopy; + button.addEventListener("click", () => { + clipboard.writeText(codeBlock.innerText).then( + () => { + button.blur(); + button.innerHTML = svgCheck; + setTimeout(() => (button.innerHTML = svgCopy), 2000); + }, + (error) => (button.innerHTML = "Error") + ); + }); + // 3. Append the button directly before the pre tag + // (with content-searching fix in place for Prism) + const pre = codeBlock.parentNode; + pre.parentNode.insertBefore(button, pre); + }); +}; + +function addCopyButtonsAfterLoad() { + if (navigator && navigator.clipboard) { + addCopyButtons(navigator.clipboard); + } else { + const script = document.createElement("script"); + script.src = + "https://cdnjs.cloudflare.com/ajax/libs/clipboard-polyfill/2.7.0/clipboard-polyfill.promise.js"; + script.integrity = + "sha256-waClS2re9NUbXRsryKoof+F9qc1gjjIhc2eT7ZbIv94="; + script.crossOrigin = "anonymous"; + script.onload = () => addCopyButtons(clipboard); + document.body.appendChild(script); + } +} + +window.addEventListener("load", addCopyButtonsAfterLoad); +``` + +As this site is a franken-baby, an 11ty site using the Minimal Mistakes theme, I needed to use `liquid` rather than `njk` code in my page layout file. So in [single.html](https://github.com/tarasis/tarasis.net/blob/main/src/_includes/layouts/single.html) I removed {% raw %}`{{content}}`{% endraw %} and replaced it with: + +{% raw %} +```liquid +{% assign Content = content %} +{% assign withoutDivStart = '
 svg {
+//	fill: gray-500;
+}
+.clipboard-button:hover {
+	cursor: pointer;
+	border-color: #01b139;
+	background-color: #87d09e;
+	opacity: 1;
+}
+.clipboard-button:hover > svg {
+	fill: #1900ff;
+}
+.clipboard-button:focus {
+	outline: 0;
+}
+// .highlight {
+//   position: relative;
+// }
+.highlight:hover > .clipboard-button {
+	opacity: 1;
+	transition: 0.2s;
+}
+
+.highlight {
+	line-height: 1.5;
+}
+```
+
+And thats it, the site now supports copying the code from the blocks at the press of a button.
+
+[^1]: I'm well aware that the following CSS should be out in its own file. Aside, the reason this file has a `liquid` file extension is that during the site build the theme is baked into it from a variable in [site.json](https://github.com/tarasis/tarasis.net/blob/main/src/_data/site.json). I then use a separate step to sass build the compiled file.
+
+[^2]: I had to do a hack to great rid of additional space that was being added despite `margin`, `padding` and anything else being set to `0`. I have tried various combinations. In theory nothing is adding `padding` or `margin` to the `table`, `tbody`, `tr`, or `td`; indeed they are explicitly set to 0. And yet there was still a chunk of spacing being added. I discovered that setting portions to `display:` `flex` & `inline-flex` solved the issue for Safari / Chrome, and `flex` and `ruby-base` for Firefox. All are hacks, but they provide the results that I want. (I was up to 4am trying to find that behaviours I wanted; not helped by Firefox not yet supporting `:has()` 🙈)
diff --git a/src/assets/css/main.scss.liquid b/src/assets/css/main.scss.liquid
index 016c908..fa1895a 100644
--- a/src/assets/css/main.scss.liquid
+++ b/src/assets/css/main.scss.liquid
@@ -147,9 +147,43 @@ div.highlight {
 	position: relative;
 }
 
-.codeblock {
-  outline: 4px #7e1c1c solid;
-  border-radius: 5px;
+div pre {
+  border: 4px #7e1c1c solid;
+  border-radius: 20px;
+}
+
+code {
+  outline: 1px #7e1c1c solid;
+}
+
+code > span {
+  padding-left: 10px;
+}
+
+// messes up table code blocks
+//code > span:first-child {
+//  padding-top: 5px;
+//}
+
+//code > span:last-child {
+//  padding-bottom: 5px;
+//}
+
+// hack to remove outline that above sets
+td > div > pre {
+  border: unset;
+}
+
+pre > code > div {
+  display: flex;
+}
+
+td {
+  display: inline-flex;
+  // below is hack so Firefox looks the same as Safari / Chrome.
+  // Both will ignore the assignment because they don't know about "ruby-base"
+  // https://caniuse.com/mdn-css_properties_display_ruby_values
+  display: ruby-base;
 }
 
 // === for copy-code-to-clipboard
@@ -187,9 +221,7 @@ div.highlight {
 .clipboard-button:focus {
 	outline: 0;
 }
-// .highlight {
-//   position: relative;
-// }
+
 .highlight:hover > .clipboard-button {
 	opacity: 1;
 	transition: 0.2s;
@@ -199,7 +231,6 @@ div.highlight {
 	line-height: 1.5;
 }
 
-
 //@import "progress.css"; // for progress bar
 //@import "minimal-mistakes/skins/{{ site.minimal_mistakes_skin | default: 'default' }}"; // skin
 @import "minimal-mistakes/skins/_{{ site.minimal_mistakes_skin | default: 'default' }}.scss"; // skin
@@ -207,3 +238,6 @@ div.highlight {
 //@import "assets/css/override-notices.scss"
 @import "override-notices.scss";
 
+.footnotes ol, .footnotes li {
+  font-size: 1em;
+}
\ No newline at end of file
diff --git a/src/assets/images/posts/copy-code-block.png b/src/assets/images/posts/copy-code-block.png
new file mode 100644
index 0000000..32f3993
Binary files /dev/null and b/src/assets/images/posts/copy-code-block.png differ