From 046b97b5fb46246dc84c77f5a60e316881f516a9 Mon Sep 17 00:00:00 2001 From: Akshat Singhai Date: Fri, 10 Jul 2026 13:38:29 +0530 Subject: [PATCH 01/11] [UI] Fix copy button shift on click and add checkmark confirmation Signed-off-by: Akshat Singhai --- assets/js/click-to-copy.js | 95 ++++++++++++++++++++++++++++++++ assets/scss/_styles_project.scss | 8 +++ 2 files changed, 103 insertions(+) create mode 100644 assets/js/click-to-copy.js diff --git a/assets/js/click-to-copy.js b/assets/js/click-to-copy.js new file mode 100644 index 00000000000..56714c96adb --- /dev/null +++ b/assets/js/click-to-copy.js @@ -0,0 +1,95 @@ +let codeListings = document.querySelectorAll('.highlight > pre'); + +for (let index = 0; index < codeListings.length; index++) { + const codeSample = codeListings[index].querySelector('code'); + const copyButton = document.createElement('button'); + const buttonAttributes = { + type: 'button', + title: 'Copy to clipboard', + 'data-bs-toggle': 'tooltip', + 'data-bs-placement': 'top', + 'data-bs-container': 'body', + }; + + Object.keys(buttonAttributes).forEach((key) => { + copyButton.setAttribute(key, buttonAttributes[key]); + }); + + copyButton.classList.add( + 'fas', + 'fa-copy', + 'btn', + 'btn-sm', + 'td-click-to-copy' + ); + const tooltip = new bootstrap.Tooltip(copyButton); + + let revertTimeout; + + copyButton.onclick = () => { + copyCode(codeSample); + copyButton.setAttribute('data-bs-original-title', 'Copied!'); + tooltip.show(); + + copyButton.classList.remove('fa-copy'); + copyButton.classList.add('fa-check', 'td-click-to-copy--copied'); + + clearTimeout(revertTimeout); + revertTimeout = setTimeout(() => { + copyButton.classList.remove('fa-check', 'td-click-to-copy--copied'); + copyButton.classList.add('fa-copy'); + copyButton.setAttribute('data-bs-original-title', 'Copy to clipboard'); + tooltip.hide(); + }, 2500); + }; + + copyButton.onmouseout = () => { + if (!copyButton.classList.contains('td-click-to-copy--copied')) { + copyButton.setAttribute('data-bs-original-title', 'Copy to clipboard'); + tooltip.hide(); + } + }; + + const buttonDiv = document.createElement('div'); + buttonDiv.classList.add('click-to-copy'); + buttonDiv.append(copyButton); + codeListings[index].insertBefore(buttonDiv, codeSample); +} + +const copyCode = (codeSample) => { + const isConsoleBlock = codeSample.matches( + "code[data-lang='console'], code.language-console" + ); + let text; + + if (isConsoleBlock) { + const clone = codeSample.cloneNode(true); + pruneUnselectableElements(codeSample, clone); + text = clone.textContent; + text = text.replace(/^ /gm, ''); + } else { + text = codeSample.textContent; + } + text = text ? text.trim() : ''; + navigator.clipboard.writeText(text + '\n'); +}; + +const pruneUnselectableElements = (sourceNode, cloneNode) => { + const sourceChildren = sourceNode.children; + const cloneChildren = cloneNode.children; + + for (let i = sourceChildren.length - 1; i >= 0; i--) { + const sourceChild = sourceChildren[i]; + const cloneChild = cloneChildren[i]; + const style = window.getComputedStyle(sourceChild); + const unselectable = + style.userSelect === 'none' || style.webkitUserSelect === 'none'; + + if (unselectable) { + cloneChild.remove(); + continue; + } + + pruneUnselectableElements(sourceChild, cloneChild); + } +}; \ No newline at end of file diff --git a/assets/scss/_styles_project.scss b/assets/scss/_styles_project.scss index 5bb83cc425a..d4462321c33 100644 --- a/assets/scss/_styles_project.scss +++ b/assets/scss/_styles_project.scss @@ -705,6 +705,14 @@ a:not([href]):not([class]):hover { &:hover { color: $body-color !important; } + + &:active { + transform: none !important; + } + + &.td-click-to-copy--copied { + color: $success !important; + } } .tooltip .tooltip-inner { From 444b0c187f081995522bed6da9f89ca30fa655b1 Mon Sep 17 00:00:00 2001 From: Akshat Singhai Date: Fri, 10 Jul 2026 13:57:28 +0530 Subject: [PATCH 02/11] Update click-to-copy.js Signed-off-by: Akshat Singhai --- assets/js/click-to-copy.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/assets/js/click-to-copy.js b/assets/js/click-to-copy.js index 56714c96adb..7881d5eae93 100644 --- a/assets/js/click-to-copy.js +++ b/assets/js/click-to-copy.js @@ -2,6 +2,11 @@ let codeListings = document.querySelectorAll('.highlight > pre'); for (let index = 0; index < codeListings.length; index++) { const codeSample = codeListings[index].querySelector('code'); + + if (!codeSample) { + continue; + } + const copyButton = document.createElement('button'); const buttonAttributes = { type: 'button', @@ -71,7 +76,11 @@ const copyCode = (codeSample) => { text = codeSample.textContent; } text = text ? text.trim() : ''; - navigator.clipboard.writeText(text + '\n'); + if (navigator.clipboard) { + navigator.clipboard.writeText(text + '\n'); + } else { + console.warn('Clipboard API is not supported in this environment.'); + } }; const pruneUnselectableElements = (sourceNode, cloneNode) => { @@ -81,10 +90,9 @@ const pruneUnselectableElements = (sourceNode, cloneNode) => { for (let i = sourceChildren.length - 1; i >= 0; i--) { const sourceChild = sourceChildren[i]; const cloneChild = cloneChildren[i]; - const style = window.getComputedStyle(sourceChild); + const style = window.getComputedStyle(sourceChild); const unselectable = - style.userSelect === 'none' || style.webkitUserSelect === 'none'; - + style && (style.userSelect === 'none' || style.webkitUserSelect === 'none'); if (unselectable) { cloneChild.remove(); continue; @@ -92,4 +100,4 @@ const pruneUnselectableElements = (sourceNode, cloneNode) => { pruneUnselectableElements(sourceChild, cloneChild); } -}; \ No newline at end of file +}; From fc14ad0c44dc4b2cd21ddb4cb16b01af154cda22 Mon Sep 17 00:00:00 2001 From: Akshat Singhai Date: Fri, 10 Jul 2026 16:01:52 +0530 Subject: [PATCH 03/11] Update click-to-copy.js Signed-off-by: Akshat Singhai --- assets/js/click-to-copy.js | 46 +++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/assets/js/click-to-copy.js b/assets/js/click-to-copy.js index 7881d5eae93..3d4b4a37847 100644 --- a/assets/js/click-to-copy.js +++ b/assets/js/click-to-copy.js @@ -32,21 +32,31 @@ for (let index = 0; index < codeListings.length; index++) { let revertTimeout; copyButton.onclick = () => { - copyCode(codeSample); - copyButton.setAttribute('data-bs-original-title', 'Copied!'); - tooltip.show(); - - copyButton.classList.remove('fa-copy'); - copyButton.classList.add('fa-check', 'td-click-to-copy--copied'); - - clearTimeout(revertTimeout); - revertTimeout = setTimeout(() => { - copyButton.classList.remove('fa-check', 'td-click-to-copy--copied'); - copyButton.classList.add('fa-copy'); - copyButton.setAttribute('data-bs-original-title', 'Copy to clipboard'); - tooltip.hide(); - }, 2500); - }; + copyCode(codeSample) + .then(() => { + copyButton.setAttribute('data-bs-original-title', 'Copied!'); + tooltip.show(); + copyButton.classList.remove('fa-copy'); + copyButton.classList.add('fa-check', 'td-click-to-copy--copied'); + clearTimeout(revertTimeout); + revertTimeout = setTimeout(() => { + copyButton.classList.remove('fa-check', 'td-click-to-copy--copied'); + copyButton.classList.add('fa-copy'); + copyButton.setAttribute('data-bs-original-title', 'Copy to clipboard'); + tooltip.hide(); + }, 2500); + }) + .catch((err) => { + console.warn('Failed to copy code to clipboard:', err); + copyButton.setAttribute('data-bs-original-title', 'Failed to copy'); + tooltip.show(); + clearTimeout(revertTimeout); + revertTimeout = setTimeout(() => { + copyButton.setAttribute('data-bs-original-title', 'Copy to clipboard'); + tooltip.hide(); + }, 2500); + }); +}; copyButton.onmouseout = () => { if (!copyButton.classList.contains('td-click-to-copy--copied')) { @@ -77,10 +87,10 @@ const copyCode = (codeSample) => { } text = text ? text.trim() : ''; if (navigator.clipboard) { - navigator.clipboard.writeText(text + '\n'); - } else { - console.warn('Clipboard API is not supported in this environment.'); + return navigator.clipboard.writeText(text + '\n'); } + console.warn('Clipboard API is not supported in this environment.'); + return Promise.reject(new Error('Clipboard API is not supported in this environment.')); }; const pruneUnselectableElements = (sourceNode, cloneNode) => { From b110093a175a7f1875fee02a5642db596f474b7c Mon Sep 17 00:00:00 2001 From: Akshat Singhai Date: Fri, 10 Jul 2026 20:32:37 +0530 Subject: [PATCH 04/11] Update click-to-copy.js Signed-off-by: Akshat Singhai --- assets/js/click-to-copy.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/assets/js/click-to-copy.js b/assets/js/click-to-copy.js index 3d4b4a37847..786cfdcf43f 100644 --- a/assets/js/click-to-copy.js +++ b/assets/js/click-to-copy.js @@ -3,10 +3,6 @@ let codeListings = document.querySelectorAll('.highlight > pre'); for (let index = 0; index < codeListings.length; index++) { const codeSample = codeListings[index].querySelector('code'); - if (!codeSample) { - continue; - } - const copyButton = document.createElement('button'); const buttonAttributes = { type: 'button', From e7ed8904f44c5071d6f86921b018f51549bf5986 Mon Sep 17 00:00:00 2001 From: Akshat Singhai Date: Fri, 10 Jul 2026 20:36:05 +0530 Subject: [PATCH 05/11] Update click-to-copy.js Signed-off-by: Akshat Singhai --- assets/js/click-to-copy.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/assets/js/click-to-copy.js b/assets/js/click-to-copy.js index 786cfdcf43f..04d44534589 100644 --- a/assets/js/click-to-copy.js +++ b/assets/js/click-to-copy.js @@ -82,12 +82,8 @@ const copyCode = (codeSample) => { text = codeSample.textContent; } text = text ? text.trim() : ''; - if (navigator.clipboard) { - return navigator.clipboard.writeText(text + '\n'); - } - console.warn('Clipboard API is not supported in this environment.'); - return Promise.reject(new Error('Clipboard API is not supported in this environment.')); -}; + return navigator.clipboard.writeText(text + '\n'); + }; const pruneUnselectableElements = (sourceNode, cloneNode) => { const sourceChildren = sourceNode.children; From d49368c9eb6266a93dd1b0d15ccc37fefbbf01d6 Mon Sep 17 00:00:00 2001 From: Akshat Singhai Date: Fri, 10 Jul 2026 20:39:09 +0530 Subject: [PATCH 06/11] Update assets/js/click-to-copy.js Co-authored-by: Bharath Valaboju <69413757+Bharath314@users.noreply.github.com> Signed-off-by: Akshat Singhai --- assets/js/click-to-copy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/js/click-to-copy.js b/assets/js/click-to-copy.js index 04d44534589..8c4992cbffe 100644 --- a/assets/js/click-to-copy.js +++ b/assets/js/click-to-copy.js @@ -92,7 +92,7 @@ const pruneUnselectableElements = (sourceNode, cloneNode) => { for (let i = sourceChildren.length - 1; i >= 0; i--) { const sourceChild = sourceChildren[i]; const cloneChild = cloneChildren[i]; - const style = window.getComputedStyle(sourceChild); + const style = window.getComputedStyle(sourceChild); const unselectable = style && (style.userSelect === 'none' || style.webkitUserSelect === 'none'); if (unselectable) { From 886cb3c24612d0100d871eff0134f35e1712d46f Mon Sep 17 00:00:00 2001 From: Akshat Singhai Date: Fri, 10 Jul 2026 20:42:33 +0530 Subject: [PATCH 07/11] Update click-to-copy.js Signed-off-by: Akshat Singhai --- assets/js/click-to-copy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/js/click-to-copy.js b/assets/js/click-to-copy.js index 8c4992cbffe..50666027136 100644 --- a/assets/js/click-to-copy.js +++ b/assets/js/click-to-copy.js @@ -94,7 +94,7 @@ const pruneUnselectableElements = (sourceNode, cloneNode) => { const cloneChild = cloneChildren[i]; const style = window.getComputedStyle(sourceChild); const unselectable = - style && (style.userSelect === 'none' || style.webkitUserSelect === 'none'); + style.userSelect === 'none' || style.webkitUserSelect === 'none'; if (unselectable) { cloneChild.remove(); continue; From 7253432794b53187d6b012ccd3b2c0862d7013ec Mon Sep 17 00:00:00 2001 From: Akshat Singhai Date: Fri, 10 Jul 2026 20:44:41 +0530 Subject: [PATCH 08/11] Update click-to-copy.js Signed-off-by: Akshat Singhai --- assets/js/click-to-copy.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/assets/js/click-to-copy.js b/assets/js/click-to-copy.js index 50666027136..22e1dfc2f04 100644 --- a/assets/js/click-to-copy.js +++ b/assets/js/click-to-copy.js @@ -53,14 +53,6 @@ for (let index = 0; index < codeListings.length; index++) { }, 2500); }); }; - - copyButton.onmouseout = () => { - if (!copyButton.classList.contains('td-click-to-copy--copied')) { - copyButton.setAttribute('data-bs-original-title', 'Copy to clipboard'); - tooltip.hide(); - } - }; - const buttonDiv = document.createElement('div'); buttonDiv.classList.add('click-to-copy'); buttonDiv.append(copyButton); From 99fbf9a3513d85711855916edd9c066bbfe8a7ac Mon Sep 17 00:00:00 2001 From: Akshat Singhai Date: Mon, 13 Jul 2026 10:48:06 +0530 Subject: [PATCH 09/11] Update click-to-copy.js Signed-off-by: Akshat Singhai --- assets/js/click-to-copy.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/assets/js/click-to-copy.js b/assets/js/click-to-copy.js index 22e1dfc2f04..35dce32e3be 100644 --- a/assets/js/click-to-copy.js +++ b/assets/js/click-to-copy.js @@ -1,5 +1,4 @@ -let codeListings = document.querySelectorAll('.highlight > pre'); - +const codeListings = document.querySelectorAll('.highlight > pre'); for (let index = 0; index < codeListings.length; index++) { const codeSample = codeListings[index].querySelector('code'); From d9057f8163649d48a4ad0dcb774cc401ec9ceede Mon Sep 17 00:00:00 2001 From: Akshat Singhai Date: Mon, 13 Jul 2026 22:33:46 +0530 Subject: [PATCH 10/11] UI: replace FontAwesome icons with Sistent copy and check icons Signed-off-by: Akshat Singhai --- assets/js/click-to-copy.js | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/assets/js/click-to-copy.js b/assets/js/click-to-copy.js index 35dce32e3be..90f62cd2e95 100644 --- a/assets/js/click-to-copy.js +++ b/assets/js/click-to-copy.js @@ -1,3 +1,7 @@ +// Sistent Icon definitions exactly as provided by the design system +const SISTENT_COPY_ICON = ``; +const SISTENT_CHECK_ICON = ``; + const codeListings = document.querySelectorAll('.highlight > pre'); for (let index = 0; index < codeListings.length; index++) { const codeSample = codeListings[index].querySelector('code'); @@ -15,13 +19,16 @@ for (let index = 0; index < codeListings.length; index++) { copyButton.setAttribute(key, buttonAttributes[key]); }); + // Removed FontAwesome classes ('fas', 'fa-copy') to keep only button styles copyButton.classList.add( - 'fas', - 'fa-copy', 'btn', 'btn-sm', 'td-click-to-copy' ); + + // Set initial Sistent Copy Icon + copyButton.innerHTML = SISTENT_COPY_ICON; + const tooltip = new bootstrap.Tooltip(copyButton); let revertTimeout; @@ -31,12 +38,17 @@ for (let index = 0; index < codeListings.length; index++) { .then(() => { copyButton.setAttribute('data-bs-original-title', 'Copied!'); tooltip.show(); - copyButton.classList.remove('fa-copy'); - copyButton.classList.add('fa-check', 'td-click-to-copy--copied'); + + // Replaced FontAwesome toggle with Sistent Check Icon + copyButton.innerHTML = SISTENT_CHECK_ICON; + copyButton.classList.add('td-click-to-copy--copied'); + clearTimeout(revertTimeout); revertTimeout = setTimeout(() => { - copyButton.classList.remove('fa-check', 'td-click-to-copy--copied'); - copyButton.classList.add('fa-copy'); + // Replaced FontAwesome toggle with Sistent Copy Icon + copyButton.innerHTML = SISTENT_COPY_ICON; + copyButton.classList.remove('td-click-to-copy--copied'); + copyButton.setAttribute('data-bs-original-title', 'Copy to clipboard'); tooltip.hide(); }, 2500); @@ -93,4 +105,4 @@ const pruneUnselectableElements = (sourceNode, cloneNode) => { pruneUnselectableElements(sourceChild, cloneChild); } -}; +}; \ No newline at end of file From 526668026dd3df30e004154e7fcdf6a48add7eaa Mon Sep 17 00:00:00 2001 From: Akshat Singhai Date: Tue, 14 Jul 2026 16:08:13 +0530 Subject: [PATCH 11/11] fix: revert copy button icons to FontAwesome, keep position-shift and checkmark fixes Signed-off-by: Akshat Singhai --- assets/js/click-to-copy.js | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/assets/js/click-to-copy.js b/assets/js/click-to-copy.js index 90f62cd2e95..e43149caf3d 100644 --- a/assets/js/click-to-copy.js +++ b/assets/js/click-to-copy.js @@ -1,7 +1,3 @@ -// Sistent Icon definitions exactly as provided by the design system -const SISTENT_COPY_ICON = ``; -const SISTENT_CHECK_ICON = ``; - const codeListings = document.querySelectorAll('.highlight > pre'); for (let index = 0; index < codeListings.length; index++) { const codeSample = codeListings[index].querySelector('code'); @@ -14,41 +10,29 @@ for (let index = 0; index < codeListings.length; index++) { 'data-bs-placement': 'top', 'data-bs-container': 'body', }; - Object.keys(buttonAttributes).forEach((key) => { copyButton.setAttribute(key, buttonAttributes[key]); }); - - // Removed FontAwesome classes ('fas', 'fa-copy') to keep only button styles copyButton.classList.add( + 'fas', + 'fa-copy', 'btn', 'btn-sm', 'td-click-to-copy' ); - - // Set initial Sistent Copy Icon - copyButton.innerHTML = SISTENT_COPY_ICON; - const tooltip = new bootstrap.Tooltip(copyButton); - let revertTimeout; - copyButton.onclick = () => { copyCode(codeSample) .then(() => { copyButton.setAttribute('data-bs-original-title', 'Copied!'); tooltip.show(); - - // Replaced FontAwesome toggle with Sistent Check Icon - copyButton.innerHTML = SISTENT_CHECK_ICON; - copyButton.classList.add('td-click-to-copy--copied'); - + copyButton.classList.remove('fa-copy'); + copyButton.classList.add('fa-check', 'td-click-to-copy--copied'); clearTimeout(revertTimeout); revertTimeout = setTimeout(() => { - // Replaced FontAwesome toggle with Sistent Copy Icon - copyButton.innerHTML = SISTENT_COPY_ICON; - copyButton.classList.remove('td-click-to-copy--copied'); - + copyButton.classList.remove('fa-check', 'td-click-to-copy--copied'); + copyButton.classList.add('fa-copy'); copyButton.setAttribute('data-bs-original-title', 'Copy to clipboard'); tooltip.hide(); }, 2500); @@ -75,7 +59,6 @@ const copyCode = (codeSample) => { "code[data-lang='console'], code.language-console" ); let text; - if (isConsoleBlock) { const clone = codeSample.cloneNode(true); pruneUnselectableElements(codeSample, clone); @@ -91,7 +74,6 @@ const copyCode = (codeSample) => { const pruneUnselectableElements = (sourceNode, cloneNode) => { const sourceChildren = sourceNode.children; const cloneChildren = cloneNode.children; - for (let i = sourceChildren.length - 1; i >= 0; i--) { const sourceChild = sourceChildren[i]; const cloneChild = cloneChildren[i]; @@ -102,7 +84,6 @@ const pruneUnselectableElements = (sourceNode, cloneNode) => { cloneChild.remove(); continue; } - pruneUnselectableElements(sourceChild, cloneChild); } }; \ No newline at end of file