diff --git a/README.md b/README.md index 63bf6a53..3404f1c0 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ It is primarily Astro, Tailwind and Typescript, with a very small amount of Soli - βœ… Markdown support - βœ… MDX Support (components in your markdown) - βœ… Searchable content (posts and projects) +- βœ… Code Blocks - copy to clipboard ## πŸ’― Lighthouse score ![Astro Sphere Lighthouse Score](_lighthouse.png) @@ -61,7 +62,6 @@ Replace npm with your package manager of choice. `npm`, `pnpm`, `yarn`, `bun`, e ## πŸ—ΊοΈ Roadmap A few features I plan to implement -- ⬜ Code Blocks - copy to clipboard - ⬜ Article Pages - Table of Contents - ⬜ Article Pages - Share on social media diff --git a/public/copy.svg b/public/copy.svg new file mode 100644 index 00000000..1adb0944 --- /dev/null +++ b/public/copy.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/js/copy.js b/public/js/copy.js new file mode 100644 index 00000000..f9cff70f --- /dev/null +++ b/public/js/copy.js @@ -0,0 +1,45 @@ +const codeBlocks = document.querySelectorAll('pre:has(code)'); + +//add copy btn to every code block on the dom +codeBlocks.forEach((code) => { + //button icon + const use = document.createElementNS('http://www.w3.org/2000/svg', 'use'); + use.setAttribute('href', '/copy.svg#empty'); + const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + svg.classList.add('copy-svg'); + svg.appendChild(use); + + //create button + const btn = document.createElement('button'); + btn.appendChild(svg); + btn.classList.add('copy-btn'); + btn.addEventListener('click', (e) => copyCode(e)); + + //container to fix copy button + const container = document.createElement('div'); + container.classList.add('copy-cnt'); + container.appendChild(btn); + + //add to code block + code.classList.add('relative'); + code.appendChild(container); +}); + +/** +* @param {MouseEvent} event +*/ +function copyCode(event) { + let codeBlock = getChildByTagName(event.currentTarget.parentElement.parentElement, 'CODE') + navigator.clipboard.writeText(codeBlock.innerText) + const use = getChildByTagName(getChildByTagName(event.currentTarget, 'svg'), 'use'); + use.setAttribute('href', '/copy.svg#filled') + setTimeout(() => { + if (use) { + use.setAttribute('href', '/copy.svg#empty') + } + }, 100); +} + +function getChildByTagName(element, tagName) { + return Array.from(element.children).find((child) => child.tagName === tagName); +} diff --git a/src/components/BaseHead.astro b/src/components/BaseHead.astro index eca0dc1e..b1826827 100644 --- a/src/components/BaseHead.astro +++ b/src/components/BaseHead.astro @@ -53,6 +53,7 @@ const { title, description, image = "/open-graph.jpg" } = Astro.props + diff --git a/src/styles/global.css b/src/styles/global.css index 9ef386f2..7e0ef18f 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -2,6 +2,10 @@ @tailwind components; @tailwind utilities; +:root{ + --copy-btn-margin:10px; +} + @layer base { @font-face { font-family: "Atkinson"; @@ -147,4 +151,18 @@ article img { #meteors .shower.ul { @apply rotate-315; -} \ No newline at end of file +} + +.copy-cnt{ + @apply absolute w-full; + top:var(--copy-btn-margin); +} +.copy-btn { + @apply w-[30px] fixed; + left:calc(100% - var(--copy-btn-margin)); + transform: translateX(-100%); +} + +.copy-svg { + @apply w-full aspect-square text-white opacity-70 hover:opacity-90; +}