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);
+ });
+ });
+ });
+});