diff --git a/config.toml b/config.toml index d1a20b3f..2b15fed5 100755 --- a/config.toml +++ b/config.toml @@ -3,7 +3,7 @@ RelativeURLs=true CanonifyURLs=true title = "Collabora Online - Community Page" copyright = "Unless a license is otherwise specified, content is under CC-BY-SA 3.0

Beaver illustrations are under Copyright © 2025 Collabora Ltd. All rights reserved." -paginate = 2 + languageCode = "en" DefaultContentLanguage = "en" enableInlineShortcodes = true @@ -53,8 +53,8 @@ type = "type" showLanguageSwitcher = false # Custom CSS and JS. Relative to /static/css and /static/js respectively. - customCSS = ["buttons.css", "anim.css", "header.css", "dropdown.css", "sidebar.css", "post-content.css"] - customJS = [] + customCSS = ["buttons.css", "anim.css", "header.css", "dropdown.css", "sidebar.css", "post-content.css", "copy-button-v2.css"] + customJS = ["copy-button.js"] [params.social] rss = true @@ -91,5 +91,8 @@ type = "type" [services.instagram] disableInlineCSS = true - [services.twitter] + [services.x] disableInlineCSS = true + +[pagination] + pagerSize = 2 diff --git a/static/css/copy-button-v2.css b/static/css/copy-button-v2.css new file mode 100644 index 00000000..c2bcf6d8 --- /dev/null +++ b/static/css/copy-button-v2.css @@ -0,0 +1,61 @@ +/* Fix positioning context */ +.highlight, +pre { + position: relative !important; +} + +.copy-button { + position: absolute !important; + top: 6px !important; + right: 6px !important; + + background: transparent !important; + background-color: transparent !important; + border: none !important; + border-radius: 4px !important; + + cursor: pointer !important; + padding: 4px !important; + z-index: 100 !important; + + transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important; + display: flex !important; + align-items: center; + justify-content: center; + + backdrop-filter: blur(2px); + appearance: none !important; + -webkit-appearance: none !important; + box-shadow: none !important; +} + +.copy-button:focus { + outline: none !important; + box-shadow: none !important; +} + +.copy-button:hover { + transform: scale(1.1) !important; + background: transparent !important; + background-color: transparent !important; +} + +.copy-button svg { + width: 16px; + height: 16px; + fill: none; + color: #333333 !important; + stroke: currentColor; + stroke-width: 2; +} + +/* Success state */ +.copy-button.copied { + background: transparent !important; + background-color: transparent !important; + border: none !important; +} + +.copy-button.copied svg { + color: #333333 !important; +} \ No newline at end of file diff --git a/static/images/check-icon.png b/static/images/check-icon.png new file mode 100644 index 00000000..59161334 Binary files /dev/null and b/static/images/check-icon.png differ diff --git a/static/images/copy-icon.png b/static/images/copy-icon.png new file mode 100644 index 00000000..114babf5 Binary files /dev/null and b/static/images/copy-icon.png differ diff --git a/static/js/copy-button.js b/static/js/copy-button.js new file mode 100644 index 00000000..44bb8ec0 --- /dev/null +++ b/static/js/copy-button.js @@ -0,0 +1,47 @@ +document.addEventListener("DOMContentLoaded", function () { + const codeBlocks = document.querySelectorAll('pre'); + + // Icon SVGs + const copyIconSvg = ''; + const checkIconSvg = ''; + + codeBlocks.forEach(function (preBlock) { + let container = preBlock; + + // Handle highlighting wrappers + if (preBlock.parentNode.classList.contains('highlight')) { + container = preBlock.parentNode; + } else if (preBlock.parentNode.tagName === 'DIV' && preBlock.parentNode.style.position === 'relative') { + container = preBlock.parentNode; + } + + container.style.position = 'relative'; + + if (container.querySelector('.copy-button')) return; + + const button = document.createElement('button'); + button.className = 'copy-button'; + button.title = 'Copy to clipboard'; + button.innerHTML = copyIconSvg; + + container.appendChild(button); + + button.addEventListener('click', function () { + button.blur(); // Remove focus + + let codeText = preBlock.textContent; + + navigator.clipboard.writeText(codeText).then(function () { + button.innerHTML = checkIconSvg; + button.classList.add('copied'); + + setTimeout(function () { + button.innerHTML = copyIconSvg; + button.classList.remove('copied'); + }, 1000); + }, function (err) { + console.error('Copy failed: ', err); + }); + }); + }); +});