diff --git a/.eslintignore b/.eslintignore index a16ec3b78eaa..05311c4695d6 100644 --- a/.eslintignore +++ b/.eslintignore @@ -10,4 +10,5 @@ website/build website/node_modules website/i18n/*.js website/translated_docs +website/static !.eslintrc.js diff --git a/package.json b/package.json index 45bc0aba16b4..d769a791a763 100644 --- a/package.json +++ b/package.json @@ -95,8 +95,8 @@ "jest-coverage": "yarn jest --coverage", "lint": "eslint . --cache --ext js,jsx,ts,tsx,md", "lint-es5-build": "eslint --no-eslintrc --no-ignore --env=browser packages/*/build-es5", - "lint:prettier": "prettier '**/*.{md,yml,yaml}' --write --ignore-path .gitignore", - "lint:prettier:ci": "prettier '**/*.{md,yml,yaml}' --check --ignore-path .gitignore", + "lint:prettier": "prettier '**/*.{md,yml,yaml}' 'website/static/**/*.{css,js}' --write --ignore-path .gitignore", + "lint:prettier:ci": "prettier '**/*.{md,yml,yaml}' 'website/static/**/*.{css,js}' --check --ignore-path .gitignore", "postinstall": "opencollective postinstall && yarn build", "install-no-ts-build": "node ./scripts/remove-postinstall && yarn --no-progress --frozen-lockfile && node ./scripts/build", "remove-prettier-dep": "node ./scripts/remove-prettier-dep", diff --git a/scripts/checkCopyrightHeaders.js b/scripts/checkCopyrightHeaders.js index af68d4c78723..12d4eb78be3c 100755 --- a/scripts/checkCopyrightHeaders.js +++ b/scripts/checkCopyrightHeaders.js @@ -102,6 +102,8 @@ const CUSTOM_IGNORED_PATTERNS = [ '^packages/expect/src/jasmineUtils\\.ts$', '^packages/jest-config/src/vendor/jsonlint\\.js$', '^packages/jest-diff/src/cleanupSemantic\\.ts$', + '^website/static/css/code-block-buttons\\.css$', + '^website/static/js/code-block-buttons\\.js', ].map(createRegExp); const IGNORED_PATTERNS = [ diff --git a/website/siteConfig.js b/website/siteConfig.js index 0fa4fb20c98f..5f0c02dc5330 100644 --- a/website/siteConfig.js +++ b/website/siteConfig.js @@ -121,7 +121,12 @@ const siteConfig = { secondaryColor: '#095708', prismColor: 'rgba(153, 66, 79, 0.03)', }, - 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: ['/css/code-block-buttons.css'], repoUrl, siteConfigUrl: 'https://github.com/facebook/jest/edit/master/website/siteConfig.js', diff --git a/website/static/css/code-block-buttons.css b/website/static/css/code-block-buttons.css new file mode 100644 index 000000000000..a6e6eef437b2 --- /dev/null +++ b/website/static/css/code-block-buttons.css @@ -0,0 +1,39 @@ +/* "Copy" code block button */ +pre { + position: relative; +} + +pre .btnIcon { + position: absolute; + top: 4px; + z-index: 2; + cursor: pointer; + border: 1px solid transparent; + padding: 0; + color: var(--green); + background-color: transparent; + height: 30px; + transition: all 0.25s ease-out; +} + +pre .btnIcon:hover { + text-decoration: none; +} + +.btnIcon__body { + align-items: center; + display: flex; +} + +.btnIcon svg { + fill: currentColor; + margin-right: 0.4em; +} + +.btnIcon__label { + font-size: 11px; +} + +.btnClipboard { + right: 10px; +} diff --git a/website/static/js/code-block-buttons.js b/website/static/js/code-block-buttons.js new file mode 100644 index 000000000000..1489a599a0bc --- /dev/null +++ b/website/static/js/code-block-buttons.js @@ -0,0 +1,45 @@ +window.addEventListener('load', function () { + function button(label, ariaLabel, icon, className) { + const btn = document.createElement('button'); + btn.classList.add('btnIcon', className); + btn.setAttribute('type', 'button'); + btn.setAttribute('aria-label', ariaLabel); + btn.innerHTML = + '
' + + icon + + '' + + label + + '' + + '
'; + return btn; + } + + function addButtons(codeBlockSelector, btn) { + document.querySelectorAll(codeBlockSelector).forEach(function (code) { + code.parentNode.appendChild(btn.cloneNode(true)); + }); + } + + const copyIcon = + ''; + + addButtons( + '.hljs', + button('Copy', 'Copy code to clipboard', copyIcon, 'btnClipboard') + ); + + const clipboard = new ClipboardJS('.btnClipboard', { + target: function (trigger) { + return trigger.parentNode.querySelector('code'); + }, + }); + + clipboard.on('success', function (event) { + event.clearSelection(); + const textEl = event.trigger.querySelector('.btnIcon__label'); + textEl.textContent = 'Copied'; + setTimeout(function () { + textEl.textContent = 'Copy'; + }, 2000); + }); +});