diff --git a/docusaurus.config.js b/docusaurus.config.js index 3288ffc7371..69c8864bda8 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -371,6 +371,12 @@ module.exports = { versions: VERSIONS_JSON, }, ], + [ + 'docusaurus-plugin-copy-page-button', + { + injectButton: false, + }, + ], ], customFields: {}, themes: [], diff --git a/package-lock.json b/package-lock.json index 1f0faeaf2c9..c7692cefa01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "clsx": "^1.1.1", "concurrently": "^6.2.0", "crowdin": "^3.5.0", + "docusaurus-plugin-copy-page-button": "^0.8.0", "docusaurus-plugin-module-alias": "^0.0.2", "docusaurus-plugin-sass": "^0.2.6", "fs-extra": "^9.1.0", @@ -8031,6 +8032,19 @@ "node": ">=6" } }, + "node_modules/docusaurus-plugin-copy-page-button": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/docusaurus-plugin-copy-page-button/-/docusaurus-plugin-copy-page-button-0.8.0.tgz", + "integrity": "sha512-WsdA9yDlOevHuKiHMq/aZJvLViyYmlyYEPtYaIvL09qScZLu27Lyx7ABycgYz10t389nnz7NcfSKD3ghMs62fg==", + "license": "MIT", + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/core": "^3.0.0", + "react": "^18.0.0 || ^19.0.0" + } + }, "node_modules/docusaurus-plugin-module-alias": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/docusaurus-plugin-module-alias/-/docusaurus-plugin-module-alias-0.0.2.tgz", diff --git a/package.json b/package.json index 6fd279bd2af..bdc9f1f3e8f 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "clsx": "^1.1.1", "concurrently": "^6.2.0", "crowdin": "^3.5.0", + "docusaurus-plugin-copy-page-button": "^0.8.0", "docusaurus-plugin-module-alias": "^0.0.2", "docusaurus-plugin-sass": "^0.2.6", "fs-extra": "^9.1.0", diff --git a/src/theme/DocItem/Footer/index.tsx b/src/theme/DocItem/Footer/index.tsx new file mode 100644 index 00000000000..1f9884a0a28 --- /dev/null +++ b/src/theme/DocItem/Footer/index.tsx @@ -0,0 +1,89 @@ +/** + * DocItemFooter renders the footer of a doc page — the tags row and the + * edit-meta row ("Edit this page" + last updated). + * + * Original source: + * @link https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/theme/DocItem/Footer/index.tsx + * + * Reason for overriding: + * - Render the "Copy page" button (docusaurus-plugin-copy-page-button) inline + * with the "Edit this page" link, styled as a peer link rather than a + * standalone button. Always show the edit-meta row so it appears on every + * doc page, not only pages that have edit/last-updated metadata. + */ + +import React from 'react'; +import clsx from 'clsx'; +import {ThemeClassNames} from '@docusaurus/theme-common'; +import {useDoc} from '@docusaurus/plugin-content-docs/client'; +import TagsListInline from '@theme/TagsListInline'; +import EditThisPage from '@theme/EditThisPage'; +import LastUpdated from '@theme/LastUpdated'; + +// CUSTOM CODE +import CopyPageButton from 'docusaurus-plugin-copy-page-button/react'; +import styles from './styles.module.css'; +// CUSTOM CODE END + +export default function DocItemFooter(): JSX.Element | null { + const {metadata} = useDoc(); + const {editUrl, lastUpdatedAt, lastUpdatedBy, tags} = metadata; + + const canDisplayTagsRow = tags.length > 0; + // CUSTOM CODE + // Always render the edit-meta row so the "Copy page" button shows on every + // doc page, even ones without an edit URL or last-updated metadata. + const canDisplayEditMetaRow = true; + // CUSTOM CODE END + const canDisplayFooter = canDisplayTagsRow || canDisplayEditMetaRow; + + if (!canDisplayFooter) { + return null; + } + + return ( + + ); +} diff --git a/src/theme/DocItem/Footer/styles.module.css b/src/theme/DocItem/Footer/styles.module.css new file mode 100644 index 00000000000..4d1754177a7 --- /dev/null +++ b/src/theme/DocItem/Footer/styles.module.css @@ -0,0 +1,55 @@ +/** + * Styles for the swizzled DocItem/Footer. + * Renders the "Copy page" button as a peer link to "Edit this page". + */ + +.editMetaActions { + display: inline-flex; + align-items: center; + flex-wrap: wrap; +} + +/* Divider between "Edit this page" and "Copy page" — only when both render */ +.editMetaActions > :not(:first-child) { + margin-left: 0.85rem; + padding-left: 0.85rem; + border-left: 1px solid var(--ifm-color-emphasis-300); +} + +.copyPageContainer { + display: inline-flex; + align-items: center; +} + +/* Strip the default button chrome so it reads as a link, matching the + * adjacent "Edit this page" link's size/weight. customStyles classes are + * appended after the plugin defaults, so override with !important. */ +.copyPageButton { + display: inline-flex !important; + align-items: center; + gap: 0.3rem; + border: none !important; + background: transparent !important; + box-shadow: none !important; + border-radius: 0 !important; + padding: 0 !important; + margin: 0 !important; + min-height: 0 !important; + /* Match the adjacent "Edit this page" anchor, which uses the Infima link color */ + color: var(--ifm-link-color) !important; + font: inherit !important; + line-height: inherit !important; + cursor: pointer; +} + +.copyPageButton:hover { + color: var(--ifm-link-hover-color, var(--ifm-link-color)) !important; + text-decoration: underline; +} + +/* Match stock EditMetaRow: right-align last-updated on desktop */ +@media (min-width: 997px) { + .lastUpdatedCol { + text-align: right; + } +}