Skip to content

Commit c2abb95

Browse files
author
Jesse Haigh
committed
update copy button position on code block scroll
1 parent 9fe7c28 commit c2abb95

File tree

1 file changed

+49
-4
lines changed

1 file changed

+49
-4
lines changed

src/components/ContentNode/CodeListing.vue

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,14 @@
2121
:fileType="fileType"
2222
>{{ fileName }}
2323
</Filename>
24-
<div class="container-general">
24+
<div class="container-general" ref="scrollContainer">
2525
<button
26+
v-show="showCopyButton"
2627
class="copy-button"
27-
:class="{ copied: isCopied }"
28+
ref="copyButton"
29+
:class="{ copied: isCopied, visible: buttonPositioned }"
2830
@click="copyToClipboard"
31+
@update="handleScroll"
2932
aria-label="Copy code to clipboard"
3033
>
3134
<svg
@@ -68,6 +71,7 @@
6871
</template>
6972

7073
<script>
74+
import debounce from 'docc-render/utils/debounce';
7175
import { escapeHtml } from 'docc-render/utils/strings';
7276
import Language from 'docc-render/constants/Language';
7377
import CodeBlock from 'docc-render/components/CodeBlock.vue';
@@ -82,8 +86,20 @@ export default {
8286
return {
8387
syntaxHighlightedLines: [],
8488
isCopied: false,
89+
showCopyButton: true,
90+
buttonPositioned: false,
91+
scrollTimeout: null,
8592
};
8693
},
94+
mounted() {
95+
this.$nextTick(() => {
96+
this.updateCopyButtonPosition();
97+
const container = this.$refs.scrollContainer;
98+
if (container) {
99+
container.addEventListener('scroll', this.handleScroll, { passive: true });
100+
}
101+
});
102+
},
87103
props: {
88104
fileName: String,
89105
isFileNameActionable: {
@@ -149,6 +165,29 @@ export default {
149165
line === '' ? '\n' : line
150166
));
151167
},
168+
updateCopyButtonPosition() {
169+
const container = this.$refs.scrollContainer;
170+
const button = this.$refs.copyButton;
171+
172+
if (!container || !button) return;
173+
174+
const { scrollLeft } = container;
175+
176+
button.style.transform = `translateX(${scrollLeft}px)`;
177+
this.buttonPositioned = true;
178+
},
179+
handleScroll: debounce(function handleScroll() {
180+
this.showCopyButton = false;
181+
this.updateCopyButtonPosition();
182+
183+
if (this.scrollTimeout) {
184+
clearTimeout(this.scrollTimeout);
185+
}
186+
187+
this.scrollTimeout = window.setTimeout(() => {
188+
this.showCopyButton = true;
189+
}, 500);
190+
}, 100),
152191
copyToClipboard() {
153192
const lines = this.content;
154193
const text = lines.join('\n');
@@ -249,17 +288,23 @@ pre {
249288
250289
.copy-button {
251290
position: absolute;
252-
top: 1em;
253-
right: 1em;
291+
top: 0.5em;
292+
right: 0.5em;
293+
transform: translateX(0);
254294
background: var(--color-fill-gray-tertiary);
255295
border: none;
256296
border-radius: 6px;
257297
padding: 7px 6px;
258298
cursor: pointer;
259299
display: none;
300+
opacity: 0;
260301
transition: all 0.2s ease-in-out;
261302
}
262303
304+
.copy-button.visible {
305+
opacity: 1;
306+
}
307+
263308
.copy-button svg {
264309
width: 24px;
265310
height: 24px;

0 commit comments

Comments
 (0)