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