create-trellis-docs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +29 -0
- package/lib/index.js +178 -0
- package/package.json +23 -0
- package/template/_gitignore +6 -0
- package/template/blog/2025-01-01-welcome.md +15 -0
- package/template/design-tokens.json +218 -0
- package/template/docs/faq/general.mdx +16 -0
- package/template/docs/faq/index.mdx +13 -0
- package/template/docs/getting-started.mdx +54 -0
- package/template/docs/guides/writing-docs.mdx +90 -0
- package/template/docusaurus.config.js.tpl +200 -0
- package/template/package.json.tpl +60 -0
- package/template/packages/faq-index-plugin/README.md +104 -0
- package/template/packages/faq-index-plugin/index.js +91 -0
- package/template/packages/faq-index-plugin/package.json +15 -0
- package/template/packages/redirects-plugin/README.md +186 -0
- package/template/packages/redirects-plugin/index.js +167 -0
- package/template/packages/redirects-plugin/package.json +15 -0
- package/template/packages/redirects-plugin/yarn.lock +31 -0
- package/template/redirects.json +1 -0
- package/template/scripts/build-tokens.js +34 -0
- package/template/sidebars.js +17 -0
- package/template/src/components/CustomSearch/CustomSearch.js +241 -0
- package/template/src/components/CustomSearch/CustomSearchContent.js +171 -0
- package/template/src/components/CustomSearch/NavbarSearch.js +211 -0
- package/template/src/components/CustomSearch/SearchContext.js +26 -0
- package/template/src/components/CustomSearch/styles.module.css +171 -0
- package/template/src/components/CustomSearch/wrapperInit.js +11 -0
- package/template/src/components/FaqTableOfContents/index.jsx +176 -0
- package/template/src/components/FaqTableOfContents/styles.module.css +167 -0
- package/template/src/components/Feedback/Feedback.js +310 -0
- package/template/src/components/Feedback/api.js +77 -0
- package/template/src/components/FlippingCard/FlippingCard.js +197 -0
- package/template/src/components/FlippingCard/styles.module.css +248 -0
- package/template/src/components/Glossary.js +57 -0
- package/template/src/css/custom.css +765 -0
- package/template/src/data/glossary.json +1 -0
- package/template/src/pages/index.js.tpl +38 -0
- package/template/src/theme/Admonition/Icon/Danger.js +11 -0
- package/template/src/theme/Admonition/Icon/Info.js +11 -0
- package/template/src/theme/Admonition/Icon/Note.js +11 -0
- package/template/src/theme/Admonition/Icon/Tip.js +11 -0
- package/template/src/theme/Admonition/Icon/Warning.js +11 -0
- package/template/src/theme/Admonition/Layout/index.js +39 -0
- package/template/src/theme/Admonition/Layout/styles.module.css +36 -0
- package/template/src/theme/Admonition/Type/Caution.js +28 -0
- package/template/src/theme/Admonition/Type/Danger.js +26 -0
- package/template/src/theme/Admonition/Type/Info.js +26 -0
- package/template/src/theme/Admonition/Type/Note.js +26 -0
- package/template/src/theme/Admonition/Type/Tip.js +26 -0
- package/template/src/theme/Admonition/Type/Warning.js +26 -0
- package/template/src/theme/Admonition/Types.js +27 -0
- package/template/src/theme/Admonition/index.js +18 -0
- package/template/src/theme/AnnouncementBar/CloseButton/index.js +20 -0
- package/template/src/theme/AnnouncementBar/CloseButton/styles.module.css +4 -0
- package/template/src/theme/AnnouncementBar/Content/index.js +17 -0
- package/template/src/theme/AnnouncementBar/Content/styles.module.css +10 -0
- package/template/src/theme/AnnouncementBar/index.js +33 -0
- package/template/src/theme/AnnouncementBar/styles.module.css +55 -0
- package/template/src/theme/BlogSidebar/Content/index.js +35 -0
- package/template/src/theme/BlogSidebar/Desktop/index.js +44 -0
- package/template/src/theme/BlogSidebar/Desktop/styles.module.css +60 -0
- package/template/src/theme/BlogSidebar/Mobile/index.js +38 -0
- package/template/src/theme/BlogSidebar/Mobile/styles.module.css +3 -0
- package/template/src/theme/BlogSidebar/index.js +15 -0
- package/template/src/theme/Details/index.js +23 -0
- package/template/src/theme/Details/styles.module.css +52 -0
- package/template/src/theme/DocBreadcrumbs/Items/Home/index.js +22 -0
- package/template/src/theme/DocBreadcrumbs/Items/Home/styles.module.css +7 -0
- package/template/src/theme/DocBreadcrumbs/StructuredData/index.js +15 -0
- package/template/src/theme/DocBreadcrumbs/index.js +75 -0
- package/template/src/theme/DocBreadcrumbs/styles.module.css +5 -0
- package/template/src/theme/DocCard/index.js +93 -0
- package/template/src/theme/DocCard/styles.module.css +53 -0
- package/template/src/theme/DocCardList/index.js +27 -0
- package/template/src/theme/DocCardList/styles.module.css +7 -0
- package/template/src/theme/DocItem/Content/index.js +121 -0
- package/template/src/theme/DocItem/Content/styles.module.css +96 -0
- package/template/src/theme/DocItem/Footer/index.js +43 -0
- package/template/src/theme/DocItem/Footer/styles.module.css +19 -0
- package/template/src/theme/DocItem/Layout/index.js +55 -0
- package/template/src/theme/DocItem/Layout/styles.module.css +14 -0
- package/template/src/theme/DocItem/Metadata/index.js +17 -0
- package/template/src/theme/DocItem/Paginator/index.js +17 -0
- package/template/src/theme/DocItem/TOC/Desktop/index.js +15 -0
- package/template/src/theme/DocItem/TOC/Mobile/index.js +17 -0
- package/template/src/theme/DocItem/TOC/Mobile/styles.module.css +12 -0
- package/template/src/theme/DocItem/index.js +19 -0
- package/template/src/theme/DocItem/styles.module.css +28 -0
- package/template/src/theme/DocRoot/Layout/Main/index.js +23 -0
- package/template/src/theme/DocRoot/Layout/Main/styles.module.css +31 -0
- package/template/src/theme/DocRoot/Layout/Sidebar/ExpandButton/index.js +28 -0
- package/template/src/theme/DocRoot/Layout/Sidebar/ExpandButton/styles.module.css +27 -0
- package/template/src/theme/DocRoot/Layout/Sidebar/index.js +70 -0
- package/template/src/theme/DocRoot/Layout/Sidebar/styles.module.css +32 -0
- package/template/src/theme/DocRoot/Layout/index.js +27 -0
- package/template/src/theme/DocRoot/Layout/styles.module.css +9 -0
- package/template/src/theme/DocRoot/index.js +25 -0
- package/template/src/theme/DocSidebar/Desktop/CollapseButton/index.js +28 -0
- package/template/src/theme/DocSidebar/Desktop/CollapseButton/styles.module.css +40 -0
- package/template/src/theme/DocSidebar/Desktop/Content/index.js +44 -0
- package/template/src/theme/DocSidebar/Desktop/Content/styles.module.css +16 -0
- package/template/src/theme/DocSidebar/Desktop/index.js +28 -0
- package/template/src/theme/DocSidebar/Desktop/styles.module.css +37 -0
- package/template/src/theme/DocSidebar/Mobile/index.js +39 -0
- package/template/src/theme/DocSidebar/index.js +18 -0
- package/template/src/theme/DocSidebarItem/Category/index.js +203 -0
- package/template/src/theme/DocSidebarItem/Html/index.js +20 -0
- package/template/src/theme/DocSidebarItem/Html/styles.module.css +6 -0
- package/template/src/theme/DocSidebarItem/Link/index.js +49 -0
- package/template/src/theme/DocSidebarItem/Link/styles.module.css +3 -0
- package/template/src/theme/DocSidebarItem/index.js +15 -0
- package/template/src/theme/EditMetaRow/index.js +25 -0
- package/template/src/theme/EditMetaRow/styles.module.css +11 -0
- package/template/src/theme/EditThisPage/index.js +29 -0
- package/template/src/theme/ErrorPageContent.js +34 -0
- package/template/src/theme/Footer/Copyright/index.js +11 -0
- package/template/src/theme/Footer/Layout/index.js +21 -0
- package/template/src/theme/Footer/LinkItem/index.js +26 -0
- package/template/src/theme/Footer/Links/MultiColumn/index.js +44 -0
- package/template/src/theme/Footer/Links/Simple/index.js +32 -0
- package/template/src/theme/Footer/Links/index.js +11 -0
- package/template/src/theme/Footer/Logo/index.js +35 -0
- package/template/src/theme/Footer/Logo/styles.module.css +9 -0
- package/template/src/theme/Footer/index.js +22 -0
- package/template/src/theme/MDXComponents/Heading.js +120 -0
- package/template/src/theme/MDXComponents/index.js +17 -0
- package/template/src/theme/MDXComponents/styles.module.css +110 -0
- package/template/src/theme/MDXContent/index.js +6 -0
- package/template/src/theme/NavbarItem/DropdownNavbarItem/Desktop/index.js +110 -0
- package/template/src/theme/NavbarItem/DropdownNavbarItem/Mobile/index.js +136 -0
- package/template/src/theme/NavbarItem/DropdownNavbarItem/Mobile/styles.module.css +3 -0
- package/template/src/theme/NavbarItem/DropdownNavbarItem/index.js +7 -0
- package/template/src/theme/NotFound/Content/index.js +46 -0
- package/template/src/theme/NotFound/index.js +19 -0
- package/template/src/theme/NotFound.js +49 -0
- package/template/src/theme/PaginatorNavLink/index.js +17 -0
- package/template/src/theme/TOC/index.js +19 -0
- package/template/src/theme/TOC/styles.module.css +16 -0
- package/template/src/theme/TOCItems/Tree.js +30 -0
- package/template/src/theme/TOCItems/index.js +47 -0
- package/template/src/theme/TabItem/index.js +15 -0
- package/template/src/theme/TabItem/styles.module.css +10 -0
- package/template/src/theme/Tabs/index.js +189 -0
- package/template/src/theme/Tabs/styles.module.css +74 -0
- package/template/static/img/favicon.svg +4 -0
- package/template/static/img/oops-404.svg +11 -0
- package/template/static/searchIndex.json +1 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import Link from '@docusaurus/Link';
|
|
4
|
+
import useBaseUrl from '@docusaurus/useBaseUrl';
|
|
5
|
+
import isInternalUrl from '@docusaurus/isInternalUrl';
|
|
6
|
+
import IconExternalLink from '@theme/Icon/ExternalLink';
|
|
7
|
+
export default function FooterLinkItem({item}) {
|
|
8
|
+
const {to, href, label, prependBaseUrlToHref, className, ...props} = item;
|
|
9
|
+
const toUrl = useBaseUrl(to);
|
|
10
|
+
const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true});
|
|
11
|
+
return (
|
|
12
|
+
<Link
|
|
13
|
+
className={clsx('footer__link-item', className)}
|
|
14
|
+
{...(href
|
|
15
|
+
? {
|
|
16
|
+
href: prependBaseUrlToHref ? normalizedHref : href,
|
|
17
|
+
}
|
|
18
|
+
: {
|
|
19
|
+
to: toUrl,
|
|
20
|
+
})}
|
|
21
|
+
{...props}>
|
|
22
|
+
{label}
|
|
23
|
+
{href && !isInternalUrl(href) && <IconExternalLink />}
|
|
24
|
+
</Link>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import {ThemeClassNames} from '@docusaurus/theme-common';
|
|
4
|
+
import LinkItem from '@theme/Footer/LinkItem';
|
|
5
|
+
function ColumnLinkItem({item}) {
|
|
6
|
+
return item.html ? (
|
|
7
|
+
<li
|
|
8
|
+
className={clsx('footer__item', item.className)}
|
|
9
|
+
// Developer provided the HTML, so assume it's safe.
|
|
10
|
+
// eslint-disable-next-line react/no-danger
|
|
11
|
+
dangerouslySetInnerHTML={{__html: item.html}}
|
|
12
|
+
/>
|
|
13
|
+
) : (
|
|
14
|
+
<li key={item.href ?? item.to} className="footer__item">
|
|
15
|
+
<LinkItem item={item} />
|
|
16
|
+
</li>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
function Column({column}) {
|
|
20
|
+
return (
|
|
21
|
+
<div
|
|
22
|
+
className={clsx(
|
|
23
|
+
ThemeClassNames.layout.footer.column,
|
|
24
|
+
'col footer__col',
|
|
25
|
+
column.className,
|
|
26
|
+
)}>
|
|
27
|
+
<div className="footer__title">{column.title}</div>
|
|
28
|
+
<ul className="footer__items clean-list">
|
|
29
|
+
{column.items.map((item, i) => (
|
|
30
|
+
<ColumnLinkItem key={i} item={item} />
|
|
31
|
+
))}
|
|
32
|
+
</ul>
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
export default function FooterLinksMultiColumn({columns}) {
|
|
37
|
+
return (
|
|
38
|
+
<div className="row footer__links">
|
|
39
|
+
{columns.map((column, i) => (
|
|
40
|
+
<Column key={i} column={column} />
|
|
41
|
+
))}
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import LinkItem from '@theme/Footer/LinkItem';
|
|
4
|
+
function Separator() {
|
|
5
|
+
return <span className="footer__link-separator">·</span>;
|
|
6
|
+
}
|
|
7
|
+
function SimpleLinkItem({item}) {
|
|
8
|
+
return item.html ? (
|
|
9
|
+
<span
|
|
10
|
+
className={clsx('footer__link-item', item.className)}
|
|
11
|
+
// Developer provided the HTML, so assume it's safe.
|
|
12
|
+
// eslint-disable-next-line react/no-danger
|
|
13
|
+
dangerouslySetInnerHTML={{__html: item.html}}
|
|
14
|
+
/>
|
|
15
|
+
) : (
|
|
16
|
+
<LinkItem item={item} />
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
export default function FooterLinksSimple({links}) {
|
|
20
|
+
return (
|
|
21
|
+
<div className="footer__links text--center">
|
|
22
|
+
<div className="footer__links">
|
|
23
|
+
{links.map((item, i) => (
|
|
24
|
+
<React.Fragment key={i}>
|
|
25
|
+
<SimpleLinkItem item={item} />
|
|
26
|
+
{links.length !== i + 1 && <Separator />}
|
|
27
|
+
</React.Fragment>
|
|
28
|
+
))}
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {isMultiColumnFooterLinks} from '@docusaurus/theme-common';
|
|
3
|
+
import FooterLinksMultiColumn from '@theme/Footer/Links/MultiColumn';
|
|
4
|
+
import FooterLinksSimple from '@theme/Footer/Links/Simple';
|
|
5
|
+
export default function FooterLinks({links}) {
|
|
6
|
+
return isMultiColumnFooterLinks(links) ? (
|
|
7
|
+
<FooterLinksMultiColumn columns={links} />
|
|
8
|
+
) : (
|
|
9
|
+
<FooterLinksSimple links={links} />
|
|
10
|
+
);
|
|
11
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import Link from '@docusaurus/Link';
|
|
4
|
+
import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
|
|
5
|
+
import ThemedImage from '@theme/ThemedImage';
|
|
6
|
+
import styles from './styles.module.css';
|
|
7
|
+
function LogoImage({logo}) {
|
|
8
|
+
const {withBaseUrl} = useBaseUrlUtils();
|
|
9
|
+
const sources = {
|
|
10
|
+
light: withBaseUrl(logo.src),
|
|
11
|
+
dark: withBaseUrl(logo.srcDark ?? logo.src),
|
|
12
|
+
};
|
|
13
|
+
return (
|
|
14
|
+
<ThemedImage
|
|
15
|
+
className={clsx('footer__logo', logo.className)}
|
|
16
|
+
alt={logo.alt}
|
|
17
|
+
sources={sources}
|
|
18
|
+
width={logo.width}
|
|
19
|
+
height={logo.height}
|
|
20
|
+
style={logo.style}
|
|
21
|
+
/>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
export default function FooterLogo({logo}) {
|
|
25
|
+
return logo.href ? (
|
|
26
|
+
<Link
|
|
27
|
+
href={logo.href}
|
|
28
|
+
className={styles.footerLogoLink}
|
|
29
|
+
target={logo.target}>
|
|
30
|
+
<LogoImage logo={logo} />
|
|
31
|
+
</Link>
|
|
32
|
+
) : (
|
|
33
|
+
<LogoImage logo={logo} />
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {useThemeConfig} from '@docusaurus/theme-common';
|
|
3
|
+
import FooterLinks from '@theme/Footer/Links';
|
|
4
|
+
import FooterLogo from '@theme/Footer/Logo';
|
|
5
|
+
import FooterCopyright from '@theme/Footer/Copyright';
|
|
6
|
+
import FooterLayout from '@theme/Footer/Layout';
|
|
7
|
+
function Footer() {
|
|
8
|
+
const {footer} = useThemeConfig();
|
|
9
|
+
if (!footer) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const {copyright, links, logo, style} = footer;
|
|
13
|
+
return (
|
|
14
|
+
<FooterLayout
|
|
15
|
+
style={style}
|
|
16
|
+
links={links && links.length > 0 && <FooterLinks links={links} />}
|
|
17
|
+
logo={logo && <FooterLogo logo={logo} />}
|
|
18
|
+
copyright={copyright && <FooterCopyright copyright={copyright} />}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
export default React.memo(Footer);
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// src/theme/MDXComponents/Heading.js
|
|
2
|
+
import React, { useState, useEffect, useRef } from 'react';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import Heading from '@theme/Heading';
|
|
5
|
+
import styles from './styles.module.css';
|
|
6
|
+
|
|
7
|
+
function LinkIcon() {
|
|
8
|
+
return (
|
|
9
|
+
<svg
|
|
10
|
+
width="16"
|
|
11
|
+
height="16"
|
|
12
|
+
viewBox="0 0 24 24"
|
|
13
|
+
fill="none"
|
|
14
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
15
|
+
>
|
|
16
|
+
<path
|
|
17
|
+
d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"
|
|
18
|
+
stroke="currentColor"
|
|
19
|
+
strokeWidth="2"
|
|
20
|
+
strokeLinecap="round"
|
|
21
|
+
strokeLinejoin="round"
|
|
22
|
+
/>
|
|
23
|
+
<path
|
|
24
|
+
d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"
|
|
25
|
+
stroke="currentColor"
|
|
26
|
+
strokeWidth="2"
|
|
27
|
+
strokeLinecap="round"
|
|
28
|
+
strokeLinejoin="round"
|
|
29
|
+
/>
|
|
30
|
+
</svg>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default function MDXHeading(props) {
|
|
35
|
+
const [showMessage, setShowMessage] = useState(false);
|
|
36
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
37
|
+
const buttonRef = useRef(null);
|
|
38
|
+
|
|
39
|
+
const canCopy = typeof window !== 'undefined' &&
|
|
40
|
+
window.navigator.clipboard &&
|
|
41
|
+
typeof window.navigator.clipboard.writeText === 'function';
|
|
42
|
+
|
|
43
|
+
const copyToClipboard = async () => {
|
|
44
|
+
if (canCopy && props.id) {
|
|
45
|
+
try {
|
|
46
|
+
const url = new URL(window.location.href);
|
|
47
|
+
url.hash = `#${props.id}`;
|
|
48
|
+
await window.navigator.clipboard.writeText(url.toString());
|
|
49
|
+
setShowMessage(true);
|
|
50
|
+
|
|
51
|
+
// Force blur using ref
|
|
52
|
+
if (buttonRef.current) {
|
|
53
|
+
buttonRef.current.blur();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Additional force blur attempts
|
|
57
|
+
if (document.activeElement instanceof HTMLElement) {
|
|
58
|
+
document.activeElement.blur();
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error('Failed to copy link:', error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (showMessage) {
|
|
68
|
+
const timer = setTimeout(() => {
|
|
69
|
+
setShowMessage(false);
|
|
70
|
+
}, 2000);
|
|
71
|
+
return () => clearTimeout(timer);
|
|
72
|
+
}
|
|
73
|
+
}, [showMessage]);
|
|
74
|
+
|
|
75
|
+
// Determine if button should be visible
|
|
76
|
+
const showButton = isHovered && !showMessage;
|
|
77
|
+
|
|
78
|
+
// Wrap the heading content with copy functionality
|
|
79
|
+
const headingContent = (
|
|
80
|
+
<span
|
|
81
|
+
className={styles.headingContent}
|
|
82
|
+
onMouseEnter={() => setIsHovered(true)}
|
|
83
|
+
onMouseLeave={() => setIsHovered(false)}
|
|
84
|
+
>
|
|
85
|
+
<span className={styles.headingText}>{props.children}</span>
|
|
86
|
+
{props.id && canCopy && (
|
|
87
|
+
<span
|
|
88
|
+
className={clsx(
|
|
89
|
+
styles.copyButtonWrapper,
|
|
90
|
+
(showButton || showMessage) && styles.visible
|
|
91
|
+
)}
|
|
92
|
+
>
|
|
93
|
+
<button
|
|
94
|
+
ref={buttonRef}
|
|
95
|
+
onClick={copyToClipboard}
|
|
96
|
+
className={styles.copyButton}
|
|
97
|
+
title="Copy link to this section"
|
|
98
|
+
type="button"
|
|
99
|
+
aria-label="Copy link to this section"
|
|
100
|
+
style={{ visibility: showButton ? 'visible' : 'hidden' }}
|
|
101
|
+
>
|
|
102
|
+
<LinkIcon />
|
|
103
|
+
</button>
|
|
104
|
+
{showMessage && (
|
|
105
|
+
<span className={styles.copyMessage} role="status" aria-live="polite">
|
|
106
|
+
Link copied!
|
|
107
|
+
</span>
|
|
108
|
+
)}
|
|
109
|
+
</span>
|
|
110
|
+
)}
|
|
111
|
+
</span>
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
// Use the default Docusaurus Heading component with our custom content
|
|
115
|
+
return (
|
|
116
|
+
<Heading {...props} className={clsx(styles.headingWithCopy, props.className)}>
|
|
117
|
+
{headingContent}
|
|
118
|
+
</Heading>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/theme/MDXComponents/index.js
|
|
2
|
+
import React from 'react';
|
|
3
|
+
// Import MDX components from Docusaurus
|
|
4
|
+
import MDXComponents from '@theme-original/MDXComponents';
|
|
5
|
+
import MDXHeading from '@theme/MDXComponents/Heading';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
// Inherit all existing MDX components
|
|
9
|
+
...MDXComponents,
|
|
10
|
+
// Override heading components with our custom implementation
|
|
11
|
+
h1: (props) => <MDXHeading as="h1" {...props} />,
|
|
12
|
+
h2: (props) => <MDXHeading as="h2" {...props} />,
|
|
13
|
+
h3: (props) => <MDXHeading as="h3" {...props} />,
|
|
14
|
+
h4: (props) => <MDXHeading as="h4" {...props} />,
|
|
15
|
+
h5: (props) => <MDXHeading as="h5" {...props} />,
|
|
16
|
+
h6: (props) => <MDXHeading as="h6" {...props} />,
|
|
17
|
+
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/* src/theme/MDXComponents/styles.module.css */
|
|
2
|
+
|
|
3
|
+
.headingWithCopy {
|
|
4
|
+
display: block;
|
|
5
|
+
position: relative;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.headingContent {
|
|
9
|
+
display: inline-flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
max-width: 100%;
|
|
12
|
+
position: relative;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.headingText {
|
|
16
|
+
flex: 1;
|
|
17
|
+
min-width: 0;
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
text-overflow: ellipsis;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.copyButtonWrapper {
|
|
23
|
+
position: relative;
|
|
24
|
+
display: inline-flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
margin-left: 8px;
|
|
27
|
+
flex-shrink: 0;
|
|
28
|
+
opacity: 0;
|
|
29
|
+
transition: opacity 0.2s ease;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* Show wrapper when it has the visible class */
|
|
33
|
+
.copyButtonWrapper.visible {
|
|
34
|
+
opacity: 1;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.copyButton {
|
|
38
|
+
display: inline-flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: center;
|
|
41
|
+
background: none;
|
|
42
|
+
border: none;
|
|
43
|
+
cursor: pointer;
|
|
44
|
+
padding: 4px;
|
|
45
|
+
color: var(--ifm-color-emphasis-600, var(--ifm-color-gray-500));
|
|
46
|
+
transition: color 0.2s, background-color 0.2s;
|
|
47
|
+
border-radius: 4px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.copyButton:hover {
|
|
51
|
+
color: var(--ifm-color-primary);
|
|
52
|
+
background-color: var(--ifm-hover-overlay);
|
|
53
|
+
border-radius: 16px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* Remove focus outline since we're controlling visibility manually */
|
|
57
|
+
.copyButton:focus {
|
|
58
|
+
outline: none;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.copyButton:focus-visible {
|
|
62
|
+
outline: 2px solid var(--ifm-color-primary);
|
|
63
|
+
outline-offset: 2px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.copyMessage {
|
|
67
|
+
position: absolute;
|
|
68
|
+
top: calc(100% + 4px);
|
|
69
|
+
right: 0;
|
|
70
|
+
background-color: var(--ifm-color-primary);
|
|
71
|
+
color: var(--ifm-color-primary-contrast-background, white);
|
|
72
|
+
padding: 4px 8px;
|
|
73
|
+
border-radius: 4px;
|
|
74
|
+
font-size: 12px;
|
|
75
|
+
white-space: nowrap;
|
|
76
|
+
opacity: 1;
|
|
77
|
+
transition: opacity 0.2s;
|
|
78
|
+
z-index: 10;
|
|
79
|
+
pointer-events: none;
|
|
80
|
+
box-shadow: var(--ifm-global-shadow-lw);
|
|
81
|
+
animation: fadeIn 0.2s ease-out;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Add animation for the copy message */
|
|
85
|
+
@keyframes fadeIn {
|
|
86
|
+
from {
|
|
87
|
+
opacity: 0;
|
|
88
|
+
transform: translateY(-4px);
|
|
89
|
+
}
|
|
90
|
+
to {
|
|
91
|
+
opacity: 1;
|
|
92
|
+
transform: translateY(0);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* Responsive adjustments - always show on mobile */
|
|
97
|
+
@media (max-width: 996px) {
|
|
98
|
+
.copyButtonWrapper {
|
|
99
|
+
opacity: 1;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.copyButton {
|
|
103
|
+
visibility: visible !important;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* Hide the default hash-link since we're replacing it with our copy button */
|
|
108
|
+
.headingWithCopy :global(.hash-link) {
|
|
109
|
+
display: none !important;
|
|
110
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import React, {useState, useRef, useEffect} from 'react';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import NavbarNavLink from '@theme/NavbarItem/NavbarNavLink';
|
|
4
|
+
import NavbarItem from '@theme/NavbarItem';
|
|
5
|
+
|
|
6
|
+
export default function DropdownNavbarItemDesktop({
|
|
7
|
+
items,
|
|
8
|
+
position,
|
|
9
|
+
className,
|
|
10
|
+
onClick,
|
|
11
|
+
...props
|
|
12
|
+
}) {
|
|
13
|
+
const dropdownRef = useRef(null);
|
|
14
|
+
const [showDropdown, setShowDropdown] = useState(false);
|
|
15
|
+
const timeoutRef = useRef(null);
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
// Clear any pending timeout when component unmounts
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
return () => {
|
|
21
|
+
if (timeoutRef.current) {
|
|
22
|
+
clearTimeout(timeoutRef.current);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}, []);
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
const handleClickOutside = (event) => {
|
|
29
|
+
if (!dropdownRef.current || dropdownRef.current.contains(event.target)) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
setShowDropdown(false);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
36
|
+
document.addEventListener('touchstart', handleClickOutside);
|
|
37
|
+
document.addEventListener('focusin', handleClickOutside);
|
|
38
|
+
|
|
39
|
+
return () => {
|
|
40
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
41
|
+
document.removeEventListener('touchstart', handleClickOutside);
|
|
42
|
+
document.removeEventListener('focusin', handleClickOutside);
|
|
43
|
+
};
|
|
44
|
+
}, [dropdownRef]);
|
|
45
|
+
|
|
46
|
+
const handleMouseEnter = () => {
|
|
47
|
+
// Clear any pending hide timeout
|
|
48
|
+
if (timeoutRef.current) {
|
|
49
|
+
clearTimeout(timeoutRef.current);
|
|
50
|
+
timeoutRef.current = null;
|
|
51
|
+
}
|
|
52
|
+
setShowDropdown(true);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const handleMouseLeave = () => {
|
|
56
|
+
// Add a small delay before hiding to prevent flickering
|
|
57
|
+
// when moving between dropdown trigger and menu
|
|
58
|
+
timeoutRef.current = setTimeout(() => {
|
|
59
|
+
setShowDropdown(false);
|
|
60
|
+
}, 150);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const handleToggleClick = (e) => {
|
|
64
|
+
e.preventDefault();
|
|
65
|
+
setShowDropdown(!showDropdown);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<div
|
|
70
|
+
ref={dropdownRef}
|
|
71
|
+
className={clsx('navbar__item', 'dropdown', {
|
|
72
|
+
'dropdown--right': position === 'right',
|
|
73
|
+
'dropdown--show': showDropdown,
|
|
74
|
+
})}
|
|
75
|
+
onMouseEnter={handleMouseEnter}
|
|
76
|
+
onMouseLeave={handleMouseLeave}>
|
|
77
|
+
<NavbarNavLink
|
|
78
|
+
aria-haspopup="true"
|
|
79
|
+
aria-expanded={showDropdown}
|
|
80
|
+
role="button"
|
|
81
|
+
href={props.to ? undefined : '#'}
|
|
82
|
+
className={clsx('navbar__link', className)}
|
|
83
|
+
{...props}
|
|
84
|
+
onClick={props.to ? undefined : handleToggleClick}
|
|
85
|
+
onKeyDown={(e) => {
|
|
86
|
+
if (e.key === 'Enter') {
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
setShowDropdown(!showDropdown);
|
|
89
|
+
}
|
|
90
|
+
}}>
|
|
91
|
+
{props.children ?? props.label}
|
|
92
|
+
</NavbarNavLink>
|
|
93
|
+
<ul className="dropdown__menu custom-dropdown__menu">
|
|
94
|
+
{items.map((childItemProps, i) => (
|
|
95
|
+
<NavbarItem
|
|
96
|
+
isDropdownItem
|
|
97
|
+
activeClassName="dropdown__link--active"
|
|
98
|
+
className="custom-dropdown__item"
|
|
99
|
+
{...childItemProps}
|
|
100
|
+
key={i}
|
|
101
|
+
onClick={() => {
|
|
102
|
+
// Close dropdown after selecting an item
|
|
103
|
+
setShowDropdown(false);
|
|
104
|
+
}}
|
|
105
|
+
/>
|
|
106
|
+
))}
|
|
107
|
+
</ul>
|
|
108
|
+
</div>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import React, {useEffect} from 'react';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import {
|
|
4
|
+
isRegexpStringMatch,
|
|
5
|
+
useCollapsible,
|
|
6
|
+
Collapsible,
|
|
7
|
+
} from '@docusaurus/theme-common';
|
|
8
|
+
import {isSamePath, useLocalPathname} from '@docusaurus/theme-common/internal';
|
|
9
|
+
import {translate} from '@docusaurus/Translate';
|
|
10
|
+
import NavbarNavLink from '@theme/NavbarItem/NavbarNavLink';
|
|
11
|
+
import NavbarItem from '@theme/NavbarItem';
|
|
12
|
+
import styles from './styles.module.css';
|
|
13
|
+
function isItemActive(item, localPathname) {
|
|
14
|
+
if (isSamePath(item.to, localPathname)) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if (isRegexpStringMatch(item.activeBaseRegex, localPathname)) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
if (item.activeBasePath && localPathname.startsWith(item.activeBasePath)) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
function containsActiveItems(items, localPathname) {
|
|
26
|
+
return items.some((item) => isItemActive(item, localPathname));
|
|
27
|
+
}
|
|
28
|
+
function CollapseButton({collapsed, onClick}) {
|
|
29
|
+
return (
|
|
30
|
+
<button
|
|
31
|
+
aria-label={
|
|
32
|
+
collapsed
|
|
33
|
+
? translate({
|
|
34
|
+
id: 'theme.navbar.mobileDropdown.collapseButton.expandAriaLabel',
|
|
35
|
+
message: 'Expand the dropdown',
|
|
36
|
+
description:
|
|
37
|
+
'The ARIA label of the button to expand the mobile dropdown navbar item',
|
|
38
|
+
})
|
|
39
|
+
: translate({
|
|
40
|
+
id: 'theme.navbar.mobileDropdown.collapseButton.collapseAriaLabel',
|
|
41
|
+
message: 'Collapse the dropdown',
|
|
42
|
+
description:
|
|
43
|
+
'The ARIA label of the button to collapse the mobile dropdown navbar item',
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
aria-expanded={!collapsed}
|
|
47
|
+
type="button"
|
|
48
|
+
className="clean-btn menu__caret"
|
|
49
|
+
onClick={onClick}
|
|
50
|
+
/>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
function useItemCollapsible({active}) {
|
|
54
|
+
const {collapsed, toggleCollapsed, setCollapsed} = useCollapsible({
|
|
55
|
+
initialState: () => !active,
|
|
56
|
+
});
|
|
57
|
+
// Expand if any item active after a navigation
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (active) {
|
|
60
|
+
setCollapsed(false);
|
|
61
|
+
}
|
|
62
|
+
}, [active, setCollapsed]);
|
|
63
|
+
return {
|
|
64
|
+
collapsed,
|
|
65
|
+
toggleCollapsed,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export default function DropdownNavbarItemMobile({
|
|
69
|
+
items,
|
|
70
|
+
className,
|
|
71
|
+
position, // Need to destructure position from props so that it doesn't get passed on.
|
|
72
|
+
onClick,
|
|
73
|
+
...props
|
|
74
|
+
}) {
|
|
75
|
+
const localPathname = useLocalPathname();
|
|
76
|
+
const isActive = isSamePath(props.to, localPathname);
|
|
77
|
+
const containsActive = containsActiveItems(items, localPathname);
|
|
78
|
+
const {collapsed, toggleCollapsed} = useItemCollapsible({
|
|
79
|
+
active: isActive || containsActive,
|
|
80
|
+
});
|
|
81
|
+
// # hash permits to make the <a> tag focusable in case no link target
|
|
82
|
+
// See https://github.com/facebook/docusaurus/pull/6003
|
|
83
|
+
// There's probably a better solution though...
|
|
84
|
+
const href = props.to ? undefined : '#';
|
|
85
|
+
return (
|
|
86
|
+
<li
|
|
87
|
+
className={clsx('menu__list-item', {
|
|
88
|
+
'menu__list-item--collapsed': collapsed,
|
|
89
|
+
})}>
|
|
90
|
+
<div
|
|
91
|
+
className={clsx('menu__list-item-collapsible', {
|
|
92
|
+
'menu__list-item-collapsible--active': isActive,
|
|
93
|
+
})}>
|
|
94
|
+
<NavbarNavLink
|
|
95
|
+
role="button"
|
|
96
|
+
className={clsx(
|
|
97
|
+
styles.dropdownNavbarItemMobile,
|
|
98
|
+
'menu__link menu__link--sublist',
|
|
99
|
+
className,
|
|
100
|
+
)}
|
|
101
|
+
href={href}
|
|
102
|
+
{...props}
|
|
103
|
+
onClick={(e) => {
|
|
104
|
+
// Prevent navigation when link is "#"
|
|
105
|
+
if (href === '#') {
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
}
|
|
108
|
+
// Otherwise we let navigation eventually happen, and/or collapse
|
|
109
|
+
toggleCollapsed();
|
|
110
|
+
}}>
|
|
111
|
+
{props.children ?? props.label}
|
|
112
|
+
</NavbarNavLink>
|
|
113
|
+
<CollapseButton
|
|
114
|
+
collapsed={collapsed}
|
|
115
|
+
onClick={(e) => {
|
|
116
|
+
e.preventDefault();
|
|
117
|
+
toggleCollapsed();
|
|
118
|
+
}}
|
|
119
|
+
/>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<Collapsible lazy as="ul" className="menu__list" collapsed={collapsed}>
|
|
123
|
+
{items.map((childItemProps, i) => (
|
|
124
|
+
<NavbarItem
|
|
125
|
+
mobile
|
|
126
|
+
isDropdownItem
|
|
127
|
+
onClick={onClick}
|
|
128
|
+
activeClassName="menu__link--active"
|
|
129
|
+
{...childItemProps}
|
|
130
|
+
key={i}
|
|
131
|
+
/>
|
|
132
|
+
))}
|
|
133
|
+
</Collapsible>
|
|
134
|
+
</li>
|
|
135
|
+
);
|
|
136
|
+
}
|