Skip to content
Open
6 changes: 6 additions & 0 deletions docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,12 @@ module.exports = {
versions: VERSIONS_JSON,
},
],
[
'docusaurus-plugin-copy-page-button',
{
injectButton: false,
},
],
],
customFields: {},
themes: [],
Expand Down
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"clsx": "^1.1.1",
"concurrently": "^6.2.0",
"crowdin": "^3.5.0",
"docusaurus-plugin-copy-page-button": "^0.8.2",
"docusaurus-plugin-module-alias": "^0.0.2",
"docusaurus-plugin-sass": "^0.2.6",
"fs-extra": "^9.1.0",
Expand Down
89 changes: 89 additions & 0 deletions src/theme/DocItem/Footer/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<footer
className={clsx(ThemeClassNames.docs.docFooter, 'docusaurus-mt-lg')}>
{canDisplayTagsRow && (
<div
className={clsx(
'row margin-top--sm',
ThemeClassNames.docs.docFooterTagsRow,
)}>
<div className="col">
<TagsListInline tags={tags} />
</div>
</div>
)}
{canDisplayEditMetaRow && (
<div
className={clsx(
'row margin-top--sm',
ThemeClassNames.docs.docFooterEditMetaRow,
)}>
<div className="col">
{/* CUSTOM CODE — "Edit this page | Copy page" as peer links on one row */}
<div className={styles.editMetaActions}>
{editUrl && <EditThisPage editUrl={editUrl} />}
<CopyPageButton
customStyles={{
container: {className: styles.copyPageContainer},
button: {className: styles.copyPageButton},
}}
/>
</div>
{/* CUSTOM CODE END */}
</div>
<div className={clsx('col', styles.lastUpdatedCol)}>
{(lastUpdatedAt || lastUpdatedBy) && (
<LastUpdated
lastUpdatedAt={lastUpdatedAt}
lastUpdatedBy={lastUpdatedBy}
/>
)}
</div>
</div>
)}
</footer>
);
}
58 changes: 58 additions & 0 deletions src/theme/DocItem/Footer/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* 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.
* Logical properties so the divider/spacing respect RTL layouts. */
.editMetaActions > :not(:first-child) {
margin-inline-start: 0.85rem;
padding-inline-start: 0.85rem;
border-inline-start: 1px solid var(--ifm-color-emphasis-300);
}

.copyPageContainer {
display: inline-flex;
align-items: center;
/* Match the "Edit this page" link's top margin so the two sit on one row */
margin-block-start: 1.25rem;
}

/* 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;
}
}