Skip to content

Commit c1b9765

Browse files
tarunrajputdotslashtarunfisker
authored
feat: add copy to clipboard in code blocks (#14153)
* feat: add copy to clipboard in code blocks * Use the same style as docusaurus v2 * Remove style from siteConfig.js * Fix typo * Disable button on copied Co-authored-by: Tarun Chauhan <tarun.chauhan@tripjack.com> Co-authored-by: fisker Cheung <lionkay@gmail.com>
1 parent 3ef82ae commit c1b9765

4 files changed

Lines changed: 128 additions & 4 deletions

File tree

website/siteConfig.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@ const siteConfig = {
5656
},
5757
usePrism: ["javascript", "jsx", "typescript", "ts", "js", "html", "css"],
5858
useEnglishUrl: true,
59-
scripts: ["https://buttons.github.io/buttons.js"],
59+
scripts: [
60+
"https://buttons.github.io/buttons.js",
61+
"https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js",
62+
"/js/code-block-buttons.js",
63+
],
6064
stylesheets: [
6165
"//unpkg.com/@sandhose/prettier-animated-logo@1.0.3/dist/wide.css",
6266
],
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/* "Copy" code block button, style from docusaurus v2 */
2+
3+
.code-block-with-actions {
4+
position: relative;
5+
}
6+
7+
.code-block-actions {
8+
position: absolute;
9+
top: 10px;
10+
right: 10px;
11+
}
12+
13+
.code-block-copy-button {
14+
width: 32px;
15+
height: 32px;
16+
border: 1px solid #dadde1;
17+
border-radius: 6px;
18+
display: flex;
19+
transition: opacity 0.2s ease-in-out;
20+
opacity: 0;
21+
position: relative;
22+
cursor: pointer;
23+
color: #393a34;
24+
background-color: #f6f8fa;
25+
}
26+
27+
.code-block-with-actions:hover .code-block-copy-button {
28+
opacity: 0.4;
29+
}
30+
31+
.code-block-with-actions:hover .code-block-copy-button:hover {
32+
opacity: 1;
33+
}
34+
35+
.code-block-copy-button__icon {
36+
fill: currentColor;
37+
position: absolute;
38+
width: 18px;
39+
height: 18px;
40+
left: 0;
41+
right: 0;
42+
top: 0;
43+
bottom: 0;
44+
margin: auto;
45+
transition: 0.15s;
46+
}
47+
48+
.code-block-copy-button__icon--copied {
49+
color: #00d600;
50+
opacity: 0;
51+
transform: scale(0.33);
52+
}
53+
54+
.code-block-copy-button--copied .code-block-copy-button__icon--copy {
55+
opacity: 0;
56+
transform: scale(0.33);
57+
}
58+
59+
.code-block-copy-button--copied .code-block-copy-button__icon--copied {
60+
transition-delay: 75ms;
61+
transform: scale(1);
62+
opacity: 1;
63+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/* global ClipboardJS */
2+
3+
"use strict";
4+
5+
(function () {
6+
const CONTAINER_CLASS_NAME = "code-block-with-actions";
7+
const ACTIONS_CONTAINER_CLASS_NAME = "code-block-actions";
8+
const COPY_BUTTON_CLASS_NAME = "code-block-copy-button";
9+
const COPY_BUTTON_COPIED_CLASS_NAME = `${COPY_BUTTON_CLASS_NAME}--copied`;
10+
const COPY_BUTTON_ICON_CLASS_NAME = `${COPY_BUTTON_CLASS_NAME}__icon`;
11+
const COPY_BUTTON_COPY_ICON_CLASS_NAME = `${COPY_BUTTON_ICON_CLASS_NAME}--copy`;
12+
const COPY_BUTTON_COPIED_ICON_CLASS_NAME = `${COPY_BUTTON_ICON_CLASS_NAME}--copied`;
13+
const ARIA_LABEL = "Copy code to clipboard";
14+
const ARIA_LABEL_COPIED = "Copied";
15+
16+
function init(codeBlock) {
17+
const container = codeBlock.parentNode;
18+
container.classList.add(CONTAINER_CLASS_NAME);
19+
20+
const actionsContainer = Object.assign(document.createElement("div"), {
21+
className: ACTIONS_CONTAINER_CLASS_NAME,
22+
});
23+
const copyButton = Object.assign(document.createElement("button"), {
24+
className: COPY_BUTTON_CLASS_NAME,
25+
type: "button",
26+
innerHTML:
27+
`<svg class="${COPY_BUTTON_ICON_CLASS_NAME} ${COPY_BUTTON_COPY_ICON_CLASS_NAME}" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg>` +
28+
`<svg class="${COPY_BUTTON_ICON_CLASS_NAME} ${COPY_BUTTON_COPIED_ICON_CLASS_NAME}" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg>`,
29+
});
30+
copyButton.setAttribute("aria-label", ARIA_LABEL);
31+
32+
new ClipboardJS(copyButton, { target: () => codeBlock }).on(
33+
"success",
34+
(event) => {
35+
event.clearSelection();
36+
copyButton.classList.add(COPY_BUTTON_COPIED_CLASS_NAME);
37+
copyButton.setAttribute("aria-label", ARIA_LABEL_COPIED);
38+
copyButton.disabled = true;
39+
40+
setTimeout(() => {
41+
copyButton.classList.remove(COPY_BUTTON_COPIED_CLASS_NAME);
42+
copyButton.setAttribute("aria-label", ARIA_LABEL);
43+
copyButton.disabled = false;
44+
}, 2000);
45+
}
46+
);
47+
48+
actionsContainer.appendChild(copyButton);
49+
container.appendChild(actionsContainer);
50+
}
51+
52+
window.addEventListener("load", () => {
53+
for (const codeBlock of document.querySelectorAll("pre > code.hljs")) {
54+
init(codeBlock);
55+
}
56+
});
57+
})();

website/yarn.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2558,9 +2558,9 @@ dashdash@^1.12.0:
25582558
assert-plus "^1.0.0"
25592559

25602560
date-fns@^2.16.1:
2561-
version "2.28.0"
2562-
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2"
2563-
integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==
2561+
version "2.29.3"
2562+
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8"
2563+
integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==
25642564

25652565
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0:
25662566
version "2.6.9"

0 commit comments

Comments
 (0)