From 18c5fa653c2a3ab4164afcdae9a53bd0b9339b94 Mon Sep 17 00:00:00 2001 From: Tarun Chauhan Date: Thu, 12 Jan 2023 21:31:07 +0530 Subject: [PATCH] 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 Co-authored-by: fisker Cheung --- website/siteConfig.js | 6 ++- website/static/css/code-block-buttons.css | 63 +++++++++++++++++++++++ website/static/js/code-block-buttons.js | 57 ++++++++++++++++++++ website/yarn.lock | 6 +-- 4 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 website/static/css/code-block-buttons.css create mode 100644 website/static/js/code-block-buttons.js diff --git a/website/siteConfig.js b/website/siteConfig.js index b4d93ab11a45..a8046d438bde 100644 --- a/website/siteConfig.js +++ b/website/siteConfig.js @@ -56,7 +56,11 @@ const siteConfig = { }, usePrism: ["javascript", "jsx", "typescript", "ts", "js", "html", "css"], useEnglishUrl: true, - scripts: ["https://buttons.github.io/buttons.js"], + scripts: [ + "https://buttons.github.io/buttons.js", + "https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js", + "/js/code-block-buttons.js", + ], stylesheets: [ "//unpkg.com/@sandhose/prettier-animated-logo@1.0.3/dist/wide.css", ], diff --git a/website/static/css/code-block-buttons.css b/website/static/css/code-block-buttons.css new file mode 100644 index 000000000000..73207981c241 --- /dev/null +++ b/website/static/css/code-block-buttons.css @@ -0,0 +1,63 @@ +/* "Copy" code block button, style from docusaurus v2 */ + +.code-block-with-actions { + position: relative; +} + +.code-block-actions { + position: absolute; + top: 10px; + right: 10px; +} + +.code-block-copy-button { + width: 32px; + height: 32px; + border: 1px solid #dadde1; + border-radius: 6px; + display: flex; + transition: opacity 0.2s ease-in-out; + opacity: 0; + position: relative; + cursor: pointer; + color: #393a34; + background-color: #f6f8fa; +} + +.code-block-with-actions:hover .code-block-copy-button { + opacity: 0.4; +} + +.code-block-with-actions:hover .code-block-copy-button:hover { + opacity: 1; +} + +.code-block-copy-button__icon { + fill: currentColor; + position: absolute; + width: 18px; + height: 18px; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; + transition: 0.15s; +} + +.code-block-copy-button__icon--copied { + color: #00d600; + opacity: 0; + transform: scale(0.33); +} + +.code-block-copy-button--copied .code-block-copy-button__icon--copy { + opacity: 0; + transform: scale(0.33); +} + +.code-block-copy-button--copied .code-block-copy-button__icon--copied { + transition-delay: 75ms; + transform: scale(1); + opacity: 1; +} diff --git a/website/static/js/code-block-buttons.js b/website/static/js/code-block-buttons.js new file mode 100644 index 000000000000..dd09911f34b6 --- /dev/null +++ b/website/static/js/code-block-buttons.js @@ -0,0 +1,57 @@ +/* global ClipboardJS */ + +"use strict"; + +(function () { + const CONTAINER_CLASS_NAME = "code-block-with-actions"; + const ACTIONS_CONTAINER_CLASS_NAME = "code-block-actions"; + const COPY_BUTTON_CLASS_NAME = "code-block-copy-button"; + const COPY_BUTTON_COPIED_CLASS_NAME = `${COPY_BUTTON_CLASS_NAME}--copied`; + const COPY_BUTTON_ICON_CLASS_NAME = `${COPY_BUTTON_CLASS_NAME}__icon`; + const COPY_BUTTON_COPY_ICON_CLASS_NAME = `${COPY_BUTTON_ICON_CLASS_NAME}--copy`; + const COPY_BUTTON_COPIED_ICON_CLASS_NAME = `${COPY_BUTTON_ICON_CLASS_NAME}--copied`; + const ARIA_LABEL = "Copy code to clipboard"; + const ARIA_LABEL_COPIED = "Copied"; + + function init(codeBlock) { + const container = codeBlock.parentNode; + container.classList.add(CONTAINER_CLASS_NAME); + + const actionsContainer = Object.assign(document.createElement("div"), { + className: ACTIONS_CONTAINER_CLASS_NAME, + }); + const copyButton = Object.assign(document.createElement("button"), { + className: COPY_BUTTON_CLASS_NAME, + type: "button", + innerHTML: + `` + + ``, + }); + copyButton.setAttribute("aria-label", ARIA_LABEL); + + new ClipboardJS(copyButton, { target: () => codeBlock }).on( + "success", + (event) => { + event.clearSelection(); + copyButton.classList.add(COPY_BUTTON_COPIED_CLASS_NAME); + copyButton.setAttribute("aria-label", ARIA_LABEL_COPIED); + copyButton.disabled = true; + + setTimeout(() => { + copyButton.classList.remove(COPY_BUTTON_COPIED_CLASS_NAME); + copyButton.setAttribute("aria-label", ARIA_LABEL); + copyButton.disabled = false; + }, 2000); + } + ); + + actionsContainer.appendChild(copyButton); + container.appendChild(actionsContainer); + } + + window.addEventListener("load", () => { + for (const codeBlock of document.querySelectorAll("pre > code.hljs")) { + init(codeBlock); + } + }); +})(); diff --git a/website/yarn.lock b/website/yarn.lock index 3abc0b3ae398..99a7ef961a5f 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -2558,9 +2558,9 @@ dashdash@^1.12.0: assert-plus "^1.0.0" date-fns@^2.16.1: - version "2.28.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" - integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== + version "2.29.3" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" + integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0: version "2.6.9"