diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index dffa79e8d3..9dfa6b17f6 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -126,6 +126,14 @@ declare module '@theme/CodeBlock' { export default function CodeBlock(props: Props): JSX.Element; } +declare module '@theme/CodeBlock/CopyButton' { + export interface Props { + readonly code: string; + } + + export default function CopyButton(props: Props): JSX.Element; +} + declare module '@theme/DocCard' { import type {PropSidebarItem} from '@docusaurus/plugin-content-docs'; diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx new file mode 100644 index 0000000000..4a02ec1306 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/index.tsx @@ -0,0 +1,65 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, {useState} from 'react'; +import clsx from 'clsx'; +import copy from 'copy-text-to-clipboard'; +import {translate} from '@docusaurus/Translate'; +import type {Props} from '@theme/CodeBlock/CopyButton'; + +import styles from './styles.module.css'; + +export default function CopyButton({code}: Props): JSX.Element { + const [isCopied, setIsCopied] = useState(false); + const handleCopyCode = () => { + copy(code); + setIsCopied(true); + + setTimeout(() => { + setIsCopied(false); + }, 2000); + }; + + return ( + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/styles.module.css b/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/styles.module.css new file mode 100644 index 0000000000..f91a3d6aac --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/CopyButton/styles.module.css @@ -0,0 +1,66 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +.copyButton { + display: flex; + background: inherit; + border: 1px solid var(--ifm-color-emphasis-300); + border-radius: var(--ifm-global-radius); + padding: 0.4rem; + position: absolute; + right: calc(var(--ifm-pre-padding) / 2); + top: calc(var(--ifm-pre-padding) / 2); + transition: opacity 200ms ease-in-out; + opacity: 0; +} + +.copyButton:focus-visible, +.copyButton:hover, +:global(.theme-code-block:hover) .copyButtonCopied { + opacity: 1 !important; +} + +:global(.theme-code-block:hover) .copyButton:not(.copyButtonCopied) { + opacity: 0.4; +} + +.copyButtonIcons { + position: relative; + width: 1.125rem; + height: 1.125rem; +} + +.copyButtonIcon, +.copyButtonSuccessIcon { + position: absolute; + top: 0; + left: 0; + fill: currentColor; + opacity: inherit; + width: inherit; + height: inherit; + transition: all 0.15s ease; +} + +.copyButtonSuccessIcon { + top: 50%; + left: 50%; + transform: translate(-50%, -50%) scale(0.33); + opacity: 0; + color: #00d600; +} + +.copyButtonCopied .copyButtonIcon { + transform: scale(0.33); + opacity: 0; +} + +.copyButtonCopied .copyButtonSuccessIcon { + transform: translate(-50%, -50%) scale(1); + opacity: 1; + transition-delay: 0.075s; +} diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx index 994f325f4c..943d3f8467 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx @@ -8,8 +8,6 @@ import React, {isValidElement, useEffect, useState} from 'react'; import clsx from 'clsx'; import Highlight, {defaultProps, type Language} from 'prism-react-renderer'; -import copy from 'copy-text-to-clipboard'; -import Translate, {translate} from '@docusaurus/Translate'; import { useThemeConfig, parseCodeBlockTitle, @@ -18,6 +16,7 @@ import { ThemeClassNames, usePrismTheme, } from '@docusaurus/theme-common'; +import CopyButton from '@theme/CodeBlock/CopyButton'; import type {Props} from '@theme/CodeBlock'; import styles from './styles.module.css'; @@ -31,7 +30,6 @@ export default function CodeBlock({ }: Props): JSX.Element { const {prism} = useThemeConfig(); - const [showCopied, setShowCopied] = useState(false); const [mounted, setMounted] = useState(false); // The Prism theme on SSR is always the default theme but the site theme // can be in a different mode. React hydration doesn't update DOM styles @@ -90,13 +88,6 @@ export default function CodeBlock({ languageProp ?? parseLanguage(blockClassName) ?? prism.defaultLanguage; const {highlightLines, code} = parseLines(content, metastring, language); - const handleCopyCode = () => { - copy(code); - setShowCopied(true); - - setTimeout(() => setShowCopied(false), 2000); - }; - return ( )} -
+
+              className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
               
                 {tokens.map((line, i) => {
                   if (line.length === 1 && line[0]!.content === '\n') {
@@ -150,29 +142,7 @@ export default function CodeBlock({
               
             
- +
)} diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css b/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css index a1bd413658..fcdcca6b1c 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css @@ -30,6 +30,7 @@ margin: 0; padding: 0; border-radius: var(--ifm-global-radius); + background-color: inherit; } .codeBlockTitle + .codeBlockContent .codeBlock { @@ -42,25 +43,6 @@ border-radius: var(--ifm-global-radius); } -.copyButton { - background: rgb(0 0 0 / 30%); - border-radius: var(--ifm-global-radius); - color: var(--ifm-color-white); - opacity: 0; - user-select: none; - padding: 0.4rem 0.5rem; - position: absolute; - right: calc(var(--ifm-pre-padding) / 2); - top: calc(var(--ifm-pre-padding) / 2); - transition: opacity 200ms ease-in-out; -} - -.copyButton:focus, -.codeBlockContent:hover > .copyButton, -.codeBlockTitle:hover + .codeBlockContent .copyButton { - opacity: 1; -} - .codeBlockLines { font: inherit; /* rtl:ignore */