From 17048ab79312f1752a296ab150984a4ef30aed5c Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Sat, 18 Apr 2026 19:02:18 +0200 Subject: refactor: syntax highlighting with Catppuccin Macchiato and copy buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add [markup.highlight] config: noClasses=false for CSS class output, lineNos=true with lineNumbersInTable=true for proper line number rendering - Create render-codeblock.html render hook to intercept fenced code blocks and wrap with header bar (language label + copy button) - Replace chroma-custom.css entirely with Catppuccin Macchiato palette (dark theme) + Catppuccin Latte (light theme), with full token color mapping - Create code-copy.js: copy-to-clipboard logic with language pretty-name map (bash→Shell, js→JavaScript, etc.), icon swap (copy→check for 2s), and aria-live region for screen reader announcement (WCAG 4.1.3) - Update baseof.html to load code-copy.js on page kind with Hugo Pipes - WCAG AA compliance: line number contrast fixed to ~3.5:1 (--ctp-overlay0), light theme copy button color to 4.1:1 (#6c6f85), focus outline 6.21:1 (--ctp-lavender), screen reader announcements via aria-live All code blocks now render with: syntax highlighting (noClasses=true fixed), line numbers with proper table layout, language label in header, copy button with feather icons, both dark and light theme support. Co-Authored-By: Claude Haiku 4.5 --- themes/danix-xyz-hacker/assets/js/code-copy.js | 79 ++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 themes/danix-xyz-hacker/assets/js/code-copy.js (limited to 'themes/danix-xyz-hacker/assets/js/code-copy.js') diff --git a/themes/danix-xyz-hacker/assets/js/code-copy.js b/themes/danix-xyz-hacker/assets/js/code-copy.js new file mode 100644 index 0000000..bfcfd4a --- /dev/null +++ b/themes/danix-xyz-hacker/assets/js/code-copy.js @@ -0,0 +1,79 @@ +(function () { + var LANG_NAMES = { + bash: 'Shell', sh: 'Shell', shell: 'Shell', zsh: 'Shell', + js: 'JavaScript', javascript: 'JavaScript', + ts: 'TypeScript', typescript: 'TypeScript', + go: 'Go', + py: 'Python', python: 'Python', + rs: 'Rust', rust: 'Rust', + html: 'HTML', + css: 'CSS', + toml: 'TOML', + yaml: 'YAML', yml: 'YAML', + json: 'JSON', + sql: 'SQL', + md: 'Markdown', markdown: 'Markdown', + c: 'C', + cpp: 'C++', 'c++': 'C++', + java: 'Java', + php: 'PHP', + ruby: 'Ruby', rb: 'Ruby', + swift: 'Swift', + kotlin: 'Kotlin', kt: 'Kotlin', + dockerfile: 'Dockerfile', + makefile: 'Makefile', + text: 'Text', txt: 'Text', + }; + + function prettyName(lang) { + if (!lang) return ''; + var key = lang.toLowerCase(); + return LANG_NAMES[key] || (lang.charAt(0).toUpperCase() + lang.slice(1)); + } + + function getCodeText(wrapper) { + var el = wrapper.querySelector('.lntd:last-child code') + || wrapper.querySelector('.code-body code') + || wrapper.querySelector('.code-body pre'); + return el ? el.innerText : ''; + } + + function initBlock(wrapper) { + var header = wrapper.querySelector('.code-header'); + if (header) { + var label = wrapper.querySelector('.code-lang-label'); + if (label) label.textContent = prettyName(header.getAttribute('data-lang') || ''); + } + + var btn = wrapper.querySelector('[data-copy-target]'); + if (!btn) return; + + btn.addEventListener('click', function () { + var text = getCodeText(wrapper); + if (!text) return; + + navigator.clipboard.writeText(text).then(function () { + var copyIcon = btn.querySelector('[data-feather="copy"]'); + var checkIcon = btn.querySelector('[data-feather="check"]'); + var liveRegion = wrapper.querySelector('.code-copy-status'); + if (copyIcon) copyIcon.style.display = 'none'; + if (checkIcon) checkIcon.classList.remove('hidden'); + btn.classList.add('is-copied'); + if (liveRegion) liveRegion.textContent = 'Code copied to clipboard.'; + + setTimeout(function () { + if (copyIcon) copyIcon.style.display = ''; + if (checkIcon) checkIcon.classList.add('hidden'); + btn.classList.remove('is-copied'); + if (liveRegion) liveRegion.textContent = ''; + }, 2000); + }).catch(function () { + // silent fail for insecure contexts + }); + }); + } + + document.addEventListener('DOMContentLoaded', function () { + document.querySelectorAll('.code-block-wrapper').forEach(initBlock); + }); +})(); -- cgit v1.2.3