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.
Files changed (148) hide show
  1. package/bin/index.js +29 -0
  2. package/lib/index.js +178 -0
  3. package/package.json +23 -0
  4. package/template/_gitignore +6 -0
  5. package/template/blog/2025-01-01-welcome.md +15 -0
  6. package/template/design-tokens.json +218 -0
  7. package/template/docs/faq/general.mdx +16 -0
  8. package/template/docs/faq/index.mdx +13 -0
  9. package/template/docs/getting-started.mdx +54 -0
  10. package/template/docs/guides/writing-docs.mdx +90 -0
  11. package/template/docusaurus.config.js.tpl +200 -0
  12. package/template/package.json.tpl +60 -0
  13. package/template/packages/faq-index-plugin/README.md +104 -0
  14. package/template/packages/faq-index-plugin/index.js +91 -0
  15. package/template/packages/faq-index-plugin/package.json +15 -0
  16. package/template/packages/redirects-plugin/README.md +186 -0
  17. package/template/packages/redirects-plugin/index.js +167 -0
  18. package/template/packages/redirects-plugin/package.json +15 -0
  19. package/template/packages/redirects-plugin/yarn.lock +31 -0
  20. package/template/redirects.json +1 -0
  21. package/template/scripts/build-tokens.js +34 -0
  22. package/template/sidebars.js +17 -0
  23. package/template/src/components/CustomSearch/CustomSearch.js +241 -0
  24. package/template/src/components/CustomSearch/CustomSearchContent.js +171 -0
  25. package/template/src/components/CustomSearch/NavbarSearch.js +211 -0
  26. package/template/src/components/CustomSearch/SearchContext.js +26 -0
  27. package/template/src/components/CustomSearch/styles.module.css +171 -0
  28. package/template/src/components/CustomSearch/wrapperInit.js +11 -0
  29. package/template/src/components/FaqTableOfContents/index.jsx +176 -0
  30. package/template/src/components/FaqTableOfContents/styles.module.css +167 -0
  31. package/template/src/components/Feedback/Feedback.js +310 -0
  32. package/template/src/components/Feedback/api.js +77 -0
  33. package/template/src/components/FlippingCard/FlippingCard.js +197 -0
  34. package/template/src/components/FlippingCard/styles.module.css +248 -0
  35. package/template/src/components/Glossary.js +57 -0
  36. package/template/src/css/custom.css +765 -0
  37. package/template/src/data/glossary.json +1 -0
  38. package/template/src/pages/index.js.tpl +38 -0
  39. package/template/src/theme/Admonition/Icon/Danger.js +11 -0
  40. package/template/src/theme/Admonition/Icon/Info.js +11 -0
  41. package/template/src/theme/Admonition/Icon/Note.js +11 -0
  42. package/template/src/theme/Admonition/Icon/Tip.js +11 -0
  43. package/template/src/theme/Admonition/Icon/Warning.js +11 -0
  44. package/template/src/theme/Admonition/Layout/index.js +39 -0
  45. package/template/src/theme/Admonition/Layout/styles.module.css +36 -0
  46. package/template/src/theme/Admonition/Type/Caution.js +28 -0
  47. package/template/src/theme/Admonition/Type/Danger.js +26 -0
  48. package/template/src/theme/Admonition/Type/Info.js +26 -0
  49. package/template/src/theme/Admonition/Type/Note.js +26 -0
  50. package/template/src/theme/Admonition/Type/Tip.js +26 -0
  51. package/template/src/theme/Admonition/Type/Warning.js +26 -0
  52. package/template/src/theme/Admonition/Types.js +27 -0
  53. package/template/src/theme/Admonition/index.js +18 -0
  54. package/template/src/theme/AnnouncementBar/CloseButton/index.js +20 -0
  55. package/template/src/theme/AnnouncementBar/CloseButton/styles.module.css +4 -0
  56. package/template/src/theme/AnnouncementBar/Content/index.js +17 -0
  57. package/template/src/theme/AnnouncementBar/Content/styles.module.css +10 -0
  58. package/template/src/theme/AnnouncementBar/index.js +33 -0
  59. package/template/src/theme/AnnouncementBar/styles.module.css +55 -0
  60. package/template/src/theme/BlogSidebar/Content/index.js +35 -0
  61. package/template/src/theme/BlogSidebar/Desktop/index.js +44 -0
  62. package/template/src/theme/BlogSidebar/Desktop/styles.module.css +60 -0
  63. package/template/src/theme/BlogSidebar/Mobile/index.js +38 -0
  64. package/template/src/theme/BlogSidebar/Mobile/styles.module.css +3 -0
  65. package/template/src/theme/BlogSidebar/index.js +15 -0
  66. package/template/src/theme/Details/index.js +23 -0
  67. package/template/src/theme/Details/styles.module.css +52 -0
  68. package/template/src/theme/DocBreadcrumbs/Items/Home/index.js +22 -0
  69. package/template/src/theme/DocBreadcrumbs/Items/Home/styles.module.css +7 -0
  70. package/template/src/theme/DocBreadcrumbs/StructuredData/index.js +15 -0
  71. package/template/src/theme/DocBreadcrumbs/index.js +75 -0
  72. package/template/src/theme/DocBreadcrumbs/styles.module.css +5 -0
  73. package/template/src/theme/DocCard/index.js +93 -0
  74. package/template/src/theme/DocCard/styles.module.css +53 -0
  75. package/template/src/theme/DocCardList/index.js +27 -0
  76. package/template/src/theme/DocCardList/styles.module.css +7 -0
  77. package/template/src/theme/DocItem/Content/index.js +121 -0
  78. package/template/src/theme/DocItem/Content/styles.module.css +96 -0
  79. package/template/src/theme/DocItem/Footer/index.js +43 -0
  80. package/template/src/theme/DocItem/Footer/styles.module.css +19 -0
  81. package/template/src/theme/DocItem/Layout/index.js +55 -0
  82. package/template/src/theme/DocItem/Layout/styles.module.css +14 -0
  83. package/template/src/theme/DocItem/Metadata/index.js +17 -0
  84. package/template/src/theme/DocItem/Paginator/index.js +17 -0
  85. package/template/src/theme/DocItem/TOC/Desktop/index.js +15 -0
  86. package/template/src/theme/DocItem/TOC/Mobile/index.js +17 -0
  87. package/template/src/theme/DocItem/TOC/Mobile/styles.module.css +12 -0
  88. package/template/src/theme/DocItem/index.js +19 -0
  89. package/template/src/theme/DocItem/styles.module.css +28 -0
  90. package/template/src/theme/DocRoot/Layout/Main/index.js +23 -0
  91. package/template/src/theme/DocRoot/Layout/Main/styles.module.css +31 -0
  92. package/template/src/theme/DocRoot/Layout/Sidebar/ExpandButton/index.js +28 -0
  93. package/template/src/theme/DocRoot/Layout/Sidebar/ExpandButton/styles.module.css +27 -0
  94. package/template/src/theme/DocRoot/Layout/Sidebar/index.js +70 -0
  95. package/template/src/theme/DocRoot/Layout/Sidebar/styles.module.css +32 -0
  96. package/template/src/theme/DocRoot/Layout/index.js +27 -0
  97. package/template/src/theme/DocRoot/Layout/styles.module.css +9 -0
  98. package/template/src/theme/DocRoot/index.js +25 -0
  99. package/template/src/theme/DocSidebar/Desktop/CollapseButton/index.js +28 -0
  100. package/template/src/theme/DocSidebar/Desktop/CollapseButton/styles.module.css +40 -0
  101. package/template/src/theme/DocSidebar/Desktop/Content/index.js +44 -0
  102. package/template/src/theme/DocSidebar/Desktop/Content/styles.module.css +16 -0
  103. package/template/src/theme/DocSidebar/Desktop/index.js +28 -0
  104. package/template/src/theme/DocSidebar/Desktop/styles.module.css +37 -0
  105. package/template/src/theme/DocSidebar/Mobile/index.js +39 -0
  106. package/template/src/theme/DocSidebar/index.js +18 -0
  107. package/template/src/theme/DocSidebarItem/Category/index.js +203 -0
  108. package/template/src/theme/DocSidebarItem/Html/index.js +20 -0
  109. package/template/src/theme/DocSidebarItem/Html/styles.module.css +6 -0
  110. package/template/src/theme/DocSidebarItem/Link/index.js +49 -0
  111. package/template/src/theme/DocSidebarItem/Link/styles.module.css +3 -0
  112. package/template/src/theme/DocSidebarItem/index.js +15 -0
  113. package/template/src/theme/EditMetaRow/index.js +25 -0
  114. package/template/src/theme/EditMetaRow/styles.module.css +11 -0
  115. package/template/src/theme/EditThisPage/index.js +29 -0
  116. package/template/src/theme/ErrorPageContent.js +34 -0
  117. package/template/src/theme/Footer/Copyright/index.js +11 -0
  118. package/template/src/theme/Footer/Layout/index.js +21 -0
  119. package/template/src/theme/Footer/LinkItem/index.js +26 -0
  120. package/template/src/theme/Footer/Links/MultiColumn/index.js +44 -0
  121. package/template/src/theme/Footer/Links/Simple/index.js +32 -0
  122. package/template/src/theme/Footer/Links/index.js +11 -0
  123. package/template/src/theme/Footer/Logo/index.js +35 -0
  124. package/template/src/theme/Footer/Logo/styles.module.css +9 -0
  125. package/template/src/theme/Footer/index.js +22 -0
  126. package/template/src/theme/MDXComponents/Heading.js +120 -0
  127. package/template/src/theme/MDXComponents/index.js +17 -0
  128. package/template/src/theme/MDXComponents/styles.module.css +110 -0
  129. package/template/src/theme/MDXContent/index.js +6 -0
  130. package/template/src/theme/NavbarItem/DropdownNavbarItem/Desktop/index.js +110 -0
  131. package/template/src/theme/NavbarItem/DropdownNavbarItem/Mobile/index.js +136 -0
  132. package/template/src/theme/NavbarItem/DropdownNavbarItem/Mobile/styles.module.css +3 -0
  133. package/template/src/theme/NavbarItem/DropdownNavbarItem/index.js +7 -0
  134. package/template/src/theme/NotFound/Content/index.js +46 -0
  135. package/template/src/theme/NotFound/index.js +19 -0
  136. package/template/src/theme/NotFound.js +49 -0
  137. package/template/src/theme/PaginatorNavLink/index.js +17 -0
  138. package/template/src/theme/TOC/index.js +19 -0
  139. package/template/src/theme/TOC/styles.module.css +16 -0
  140. package/template/src/theme/TOCItems/Tree.js +30 -0
  141. package/template/src/theme/TOCItems/index.js +47 -0
  142. package/template/src/theme/TabItem/index.js +15 -0
  143. package/template/src/theme/TabItem/styles.module.css +10 -0
  144. package/template/src/theme/Tabs/index.js +189 -0
  145. package/template/src/theme/Tabs/styles.module.css +74 -0
  146. package/template/static/img/favicon.svg +4 -0
  147. package/template/static/img/oops-404.svg +11 -0
  148. 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,9 @@
1
+ .footerLogoLink {
2
+ opacity: 0.5;
3
+ transition: opacity var(--ifm-transition-fast)
4
+ var(--ifm-transition-timing-default);
5
+ }
6
+
7
+ .footerLogoLink:hover {
8
+ opacity: 1;
9
+ }
@@ -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,6 @@
1
+ import React from 'react';
2
+ import {MDXProvider} from '@mdx-js/react';
3
+ import MDXComponents from '@theme/MDXComponents';
4
+ export default function MDXContent({children}) {
5
+ return <MDXProvider components={MDXComponents}>{children}</MDXProvider>;
6
+ }
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+ .dropdownNavbarItemMobile {
2
+ cursor: pointer;
3
+ }