Skip to content

Commit 2091d00

Browse files
authored
Merge pull request #2 from echennells/feature/copy-buttons
Add copy buttons for shell commands
2 parents ac25a86 + df0b3d2 commit 2091d00

2 files changed

Lines changed: 158 additions & 1 deletion

File tree

_includes/copy_code_button.html

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
<script>
2+
document.addEventListener('DOMContentLoaded', function() {
3+
// Target only shell/bash command blocks (marked with ```shell in markdown)
4+
const codeBlocks = document.querySelectorAll('.language-shell');
5+
6+
codeBlocks.forEach(function(block) {
7+
// Skip if already has copy button
8+
if (block.querySelector('.copy-btn')) return;
9+
10+
const pre = block.querySelector('pre');
11+
if (!pre) return;
12+
13+
// Create copy button
14+
const copyBtn = document.createElement('button');
15+
copyBtn.className = 'copy-btn';
16+
copyBtn.innerHTML = '📋';
17+
copyBtn.setAttribute('data-tooltip', 'Copy');
18+
19+
// Position button
20+
block.style.position = 'relative';
21+
block.appendChild(copyBtn);
22+
23+
// Copy functionality
24+
copyBtn.addEventListener('click', function() {
25+
const code = (pre.textContent || pre.innerText).trim();
26+
27+
if (navigator.clipboard) {
28+
navigator.clipboard.writeText(code).then(function() {
29+
showSuccess(copyBtn);
30+
}).catch(function() {
31+
fallbackCopy(code, copyBtn);
32+
});
33+
} else {
34+
fallbackCopy(code, copyBtn);
35+
}
36+
});
37+
});
38+
39+
function showSuccess(button) {
40+
const original = button.innerHTML;
41+
button.innerHTML = '✅';
42+
button.setAttribute('data-tooltip', 'Copied!');
43+
button.style.backgroundColor = '#22c55e';
44+
45+
setTimeout(function() {
46+
button.innerHTML = original;
47+
button.setAttribute('data-tooltip', 'Copy');
48+
button.style.backgroundColor = '';
49+
}, 2000);
50+
}
51+
52+
function fallbackCopy(text, button) {
53+
const textArea = document.createElement('textarea');
54+
textArea.value = text;
55+
textArea.style.position = 'fixed';
56+
textArea.style.left = '-9999px';
57+
document.body.appendChild(textArea);
58+
textArea.select();
59+
60+
try {
61+
document.execCommand('copy');
62+
showSuccess(button);
63+
} catch (err) {
64+
console.error('Copy failed:', err);
65+
}
66+
67+
document.body.removeChild(textArea);
68+
}
69+
});
70+
</script>
71+
72+
<style>
73+
.copy-btn {
74+
position: absolute;
75+
top: 8px;
76+
right: 8px;
77+
background: rgba(0, 0, 0, 0.7);
78+
border: none;
79+
border-radius: 4px;
80+
color: white;
81+
padding: 4px 8px;
82+
cursor: pointer;
83+
font-size: 14px;
84+
opacity: 0.7;
85+
transition: all 0.2s ease;
86+
z-index: 10;
87+
}
88+
89+
.copy-btn:hover {
90+
opacity: 1;
91+
transform: scale(1.1);
92+
}
93+
94+
.copy-btn:active {
95+
transform: scale(0.9);
96+
}
97+
98+
/* Tooltip */
99+
.copy-btn::before {
100+
content: attr(data-tooltip);
101+
position: absolute;
102+
bottom: 100%;
103+
right: 0;
104+
background: rgba(0, 0, 0, 0.9);
105+
color: white;
106+
padding: 4px 8px;
107+
border-radius: 4px;
108+
font-size: 12px;
109+
white-space: nowrap;
110+
opacity: 0;
111+
visibility: hidden;
112+
transition: opacity 0.2s ease, visibility 0.2s ease;
113+
transform: translateY(-4px);
114+
z-index: 11;
115+
}
116+
117+
.copy-btn::after {
118+
content: '';
119+
position: absolute;
120+
bottom: 100%;
121+
right: 8px;
122+
border: 4px solid transparent;
123+
border-top-color: rgba(0, 0, 0, 0.9);
124+
opacity: 0;
125+
visibility: hidden;
126+
transition: opacity 0.2s ease, visibility 0.2s ease;
127+
transform: translateY(-4px);
128+
}
129+
130+
.copy-btn:hover::before,
131+
.copy-btn:hover::after {
132+
opacity: 1;
133+
visibility: visible;
134+
transform: translateY(-8px);
135+
}
136+
137+
/* Dark theme compatibility */
138+
[data-theme="dark"] .copy-btn {
139+
background: rgba(255, 255, 255, 0.2);
140+
color: #e5e5e5;
141+
}
142+
143+
[data-theme="dark"] .copy-btn::before {
144+
background: rgba(255, 255, 255, 0.95);
145+
color: #1a1a1a;
146+
}
147+
148+
[data-theme="dark"] .copy-btn::after {
149+
border-top-color: rgba(255, 255, 255, 0.95);
150+
}
151+
152+
[data-theme="light"] .copy-btn {
153+
background: rgba(0, 0, 0, 0.7);
154+
color: white;
155+
}
156+
</style>

_includes/head.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
{% endif %}
3333

3434
{%- include custom_head.html -%}
35-
35+
{% include copy_code_button.html %}
36+
3637
<!-- Lightning address -->
3738
<meta name="lightning" content="lnurlp:support@nodeacademy.org"/>
3839
<meta property="og:image" content="logo.png" />

0 commit comments

Comments
 (0)