Skip to content

Commit cb7a90d

Browse files
authored
Merge pull request #15759 from vedansha07/add-copy-button
Add copy-to-clipboard feature for code blocks in docs
2 parents d99b9c7 + 7628f3c commit cb7a90d

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed

docs/css/copy-code.css

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* Base button placement & visibility */
2+
.copy-btn {
3+
position: absolute;
4+
top: 6px;
5+
right: 6px;
6+
background: transparent;
7+
border: none;
8+
padding: 4px;
9+
cursor: pointer;
10+
11+
opacity: 0;
12+
transform: translateY(-3px);
13+
transition: opacity 0.18s ease, transform 0.18s ease, color 0.2s ease;
14+
15+
display: flex;
16+
align-items: center;
17+
justify-content: center;
18+
19+
color: #666; /* default icon color */
20+
}
21+
22+
/* Show button only when the code block is hovered */
23+
pre:hover .copy-btn {
24+
opacity: 1;
25+
transform: translateY(0);
26+
}
27+
28+
/* Hover state always forces black — applies to both icons */
29+
.copy-btn:hover {
30+
color: #000 !important;
31+
}
32+
33+
/* Tick icon uses the same neutral grey so hover can override cleanly */
34+
.copy-btn.copied {
35+
color: #666;
36+
}
37+
38+
/* Icon sizing + smooth color transition */
39+
.copy-btn svg {
40+
width: 20px;
41+
height: 20px;
42+
transition: color 0.2s ease;
43+
}

docs/js/copy-code.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict';
2+
3+
// Attach copy-button logic only after the full DOM is loaded
4+
document.addEventListener('DOMContentLoaded', () => {
5+
// Inline SVG icons so no external asset load is required
6+
const copyIcon = `
7+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
8+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
9+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
10+
</svg>
11+
`;
12+
13+
const checkIcon = `
14+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
15+
<path d="M20 6L9 17l-5-5"></path>
16+
</svg>
17+
`;
18+
19+
// Inject a copy button into each <pre><code> block used in docs
20+
document.querySelectorAll('pre code').forEach(block => {
21+
const wrapper = block.parentElement;
22+
wrapper.style.position = 'relative'; // ensures button can be positioned correctly
23+
24+
const btn = document.createElement('button');
25+
btn.className = 'copy-btn';
26+
btn.setAttribute('aria-label', 'Copy code to clipboard'); // accessibility support
27+
btn.innerHTML = copyIcon; // initial icon state
28+
29+
// Handle the copy-to-clipboard action
30+
btn.onclick = async() => {
31+
if (btn.dataset.locked) return; // prevents multiple fast clicks
32+
btn.dataset.locked = '1';
33+
34+
// Uses Clipboard API to copy code block text
35+
await navigator.clipboard.writeText(block.textContent);
36+
37+
// Show success tick briefly
38+
btn.innerHTML = checkIcon;
39+
btn.classList.add('copied');
40+
41+
// Restore original icon after delay
42+
setTimeout(() => {
43+
btn.innerHTML = copyIcon;
44+
btn.classList.remove('copied');
45+
btn.dataset.locked = '';
46+
}, 1200);
47+
};
48+
49+
wrapper.appendChild(btn); // attach button to code block
50+
});
51+
});

docs/layout.pug

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ html(lang='en')
1313
link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/github.css`)
1414
link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/mongoose5.css`)
1515
link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/carbonads.css`)
16+
link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/copy-code.css`)
17+
1618

1719
meta(name='msapplication-TileColor', content='#ffffff')
1820
meta(name='msapplication-TileImage', content=`${versions.versionedPath}/docs/images/favicon/ms-icon-144x144.png`)
@@ -172,3 +174,6 @@ html(lang='en')
172174

173175
script(type="text/javascript" src=`${versions.versionedPath}/docs/js/navbar-search.js`)
174176
script(type="text/javascript" src=`${versions.versionedPath}/docs/js/mobile-navbar-toggle.js`)
177+
178+
script(type="text/javascript" src=`${versions.versionedPath}/docs/js/copy-code.js`)
179+

0 commit comments

Comments
 (0)