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,7 @@
1
+ import React from 'react';
2
+ import DropdownNavbarItemMobile from '@theme/NavbarItem/DropdownNavbarItem/Mobile';
3
+ import DropdownNavbarItemDesktop from '@theme/NavbarItem/DropdownNavbarItem/Desktop';
4
+ export default function DropdownNavbarItem({mobile = false, ...props}) {
5
+ const Comp = mobile ? DropdownNavbarItemMobile : DropdownNavbarItemDesktop;
6
+ return <Comp {...props} />;
7
+ }
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import Translate, { translate } from '@docusaurus/Translate';
3
+ import { PageMetadata } from '@docusaurus/theme-common';
4
+
5
+ export default function NotFound() {
6
+ return (
7
+ <>
8
+ <PageMetadata
9
+ title={translate({
10
+ id: 'theme.NotFound.title',
11
+ message: 'Page Not Found',
12
+ })}
13
+ />
14
+ <main className="container conver-404 margin-vert--xl">
15
+ <div className="row">
16
+ <div className="col col--6 col--offset-3">
17
+ <h1 className="hero__title not-found">
18
+ <Translate
19
+ id="theme.NotFound.title"
20
+ description="The title of the 404 page"
21
+ >
22
+ Page Not Found
23
+ </Translate>
24
+ </h1>
25
+ <p className="not-found">
26
+ <Translate
27
+ id="theme.NotFound.p1"
28
+ description="The first paragraph of the 404 page"
29
+ >
30
+ The link you clicked may be broken or the page may have been
31
+ removed.
32
+ </Translate>
33
+ </p>
34
+ <div className="intro-text-button">
35
+ <div>
36
+ <a className="button button--primary button-404" href="/">
37
+ Go Home!
38
+ </a>
39
+ </div>
40
+ </div>
41
+ </div>
42
+ </div>
43
+ </main>
44
+ </>
45
+ );
46
+ }
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import {translate} from '@docusaurus/Translate';
3
+ import {PageMetadata} from '@docusaurus/theme-common';
4
+ import Layout from '@theme/Layout';
5
+ import NotFoundContent from '@theme/NotFound/Content';
6
+ export default function Index() {
7
+ const title = translate({
8
+ id: 'theme.NotFound.title',
9
+ message: 'Page Not Found',
10
+ });
11
+ return (
12
+ <>
13
+ <PageMetadata title={title} />
14
+ <Layout>
15
+ <NotFoundContent />
16
+ </Layout>
17
+ </>
18
+ );
19
+ }
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import Translate, { translate } from '@docusaurus/Translate';
3
+ import { PageMetadata } from '@docusaurus/theme-common';
4
+ import Layout from '@theme/Layout';
5
+
6
+ export default function NotFound() {
7
+ return (
8
+ <>
9
+ <PageMetadata
10
+ title={translate({
11
+ id: 'theme.NotFound.title',
12
+ message: 'Page Not Found',
13
+ })}
14
+ />
15
+ <Layout className="conver-404">
16
+ <main className="container margin-vert--xl">
17
+ <div className="row">
18
+ <div className="col col--6 col--offset-3">
19
+ <h1 className="hero__title not-found">
20
+ <Translate
21
+ id="theme.NotFound.title"
22
+ description="The title of the 404 page"
23
+ >
24
+ Page Not Found
25
+ </Translate>
26
+ </h1>
27
+ <p className="not-found">
28
+ <Translate
29
+ id="theme.NotFound.p1"
30
+ description="The first paragraph of the 404 page"
31
+ >
32
+ The link you clicked may be broken or the page may have been
33
+ removed.
34
+ </Translate>
35
+ </p>
36
+ <div className="intro-text-button">
37
+ <div>
38
+ <a className="button button--primary button-404" href="/">
39
+ Go Home!
40
+ </a>
41
+ </div>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ </main>
46
+ </Layout>
47
+ </>
48
+ );
49
+ }
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import clsx from 'clsx';
3
+ import Link from '@docusaurus/Link';
4
+ export default function PaginatorNavLink(props) {
5
+ const {permalink, title, subLabel, isNext} = props;
6
+ return (
7
+ <Link
8
+ className={clsx(
9
+ 'pagination-nav__link',
10
+ isNext ? 'pagination-nav__link--next' : 'pagination-nav__link--prev',
11
+ )}
12
+ to={permalink}>
13
+ {subLabel && <div className="pagination-nav__sublabel">{subLabel}</div>}
14
+ <div className="pagination-nav__label">{title}</div>
15
+ </Link>
16
+ );
17
+ }
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import clsx from 'clsx';
3
+ import TOCItems from '@theme/TOCItems';
4
+ import styles from './styles.module.css';
5
+ // Using a custom className
6
+ // This prevents TOCInline/TOCCollapsible getting highlighted by mistake
7
+ const LINK_CLASS_NAME = 'table-of-contents__link toc-highlight';
8
+ const LINK_ACTIVE_CLASS_NAME = 'table-of-contents__link--active';
9
+ export default function TOC({className, ...props}) {
10
+ return (
11
+ <div className={clsx(styles.tableOfContents, 'thin-scrollbar', className)}>
12
+ <TOCItems
13
+ {...props}
14
+ linkClassName={LINK_CLASS_NAME}
15
+ linkActiveClassName={LINK_ACTIVE_CLASS_NAME}
16
+ />
17
+ </div>
18
+ );
19
+ }
@@ -0,0 +1,16 @@
1
+ .tableOfContents {
2
+ max-height: calc(100vh - (var(--ifm-navbar-height) + 2rem));
3
+ overflow-y: auto;
4
+ position: sticky;
5
+ top: calc(var(--ifm-navbar-height) + 1rem);
6
+ }
7
+
8
+ @media (max-width: 996px) {
9
+ .tableOfContents {
10
+ display: none;
11
+ }
12
+
13
+ .docItemContainer {
14
+ padding: 0 0.3rem;
15
+ }
16
+ }
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import Link from '@docusaurus/Link';
3
+ // Recursive component rendering the toc tree
4
+ function TOCItemTree({toc, className, linkClassName, isChild}) {
5
+ if (!toc.length) {
6
+ return null;
7
+ }
8
+ return (
9
+ <ul className={isChild ? undefined : className}>
10
+ {toc.map((heading) => (
11
+ <li key={heading.id}>
12
+ <Link
13
+ to={`#${heading.id}`}
14
+ className={linkClassName ?? undefined}
15
+ // Developer provided the HTML, so assume it's safe.
16
+ dangerouslySetInnerHTML={{__html: heading.value}}
17
+ />
18
+ <TOCItemTree
19
+ isChild
20
+ toc={heading.children}
21
+ className={className}
22
+ linkClassName={linkClassName}
23
+ />
24
+ </li>
25
+ ))}
26
+ </ul>
27
+ );
28
+ }
29
+ // Memo only the tree root is enough
30
+ export default React.memo(TOCItemTree);
@@ -0,0 +1,47 @@
1
+ import React, {useMemo} from 'react';
2
+ import {useThemeConfig} from '@docusaurus/theme-common';
3
+ import {
4
+ useTOCHighlight,
5
+ useFilteredAndTreeifiedTOC,
6
+ } from '@docusaurus/theme-common/internal';
7
+ import TOCItemTree from '@theme/TOCItems/Tree';
8
+ export default function TOCItems({
9
+ toc,
10
+ className = 'table-of-contents table-of-contents__left-border',
11
+ linkClassName = 'table-of-contents__link',
12
+ linkActiveClassName = undefined,
13
+ minHeadingLevel: minHeadingLevelOption,
14
+ maxHeadingLevel: maxHeadingLevelOption,
15
+ ...props
16
+ }) {
17
+ const themeConfig = useThemeConfig();
18
+ const minHeadingLevel =
19
+ minHeadingLevelOption ?? themeConfig.tableOfContents.minHeadingLevel;
20
+ const maxHeadingLevel =
21
+ maxHeadingLevelOption ?? themeConfig.tableOfContents.maxHeadingLevel;
22
+ const tocTree = useFilteredAndTreeifiedTOC({
23
+ toc,
24
+ minHeadingLevel,
25
+ maxHeadingLevel,
26
+ });
27
+ const tocHighlightConfig = useMemo(() => {
28
+ if (linkClassName && linkActiveClassName) {
29
+ return {
30
+ linkClassName,
31
+ linkActiveClassName,
32
+ minHeadingLevel,
33
+ maxHeadingLevel,
34
+ };
35
+ }
36
+ return undefined;
37
+ }, [linkClassName, linkActiveClassName, minHeadingLevel, maxHeadingLevel]);
38
+ useTOCHighlight(tocHighlightConfig);
39
+ return (
40
+ <TOCItemTree
41
+ toc={tocTree}
42
+ className={className}
43
+ linkClassName={linkClassName}
44
+ {...props}
45
+ />
46
+ );
47
+ }
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import clsx from 'clsx';
3
+ import styles from './styles.module.css';
4
+
5
+ export default function TabItem({ children, hidden, className }) {
6
+ return (
7
+ <div
8
+ role="tabpanel"
9
+ className={clsx(styles.tabItemContent, className)}
10
+ {...{ hidden }}
11
+ >
12
+ {children}
13
+ </div>
14
+ );
15
+ }
@@ -0,0 +1,10 @@
1
+ .tabItem > *:last-child {
2
+ margin-bottom: 0;
3
+ }
4
+
5
+ .tabItemContent {
6
+ padding: 0.25rem 1rem;
7
+ border-radius: 0.5rem;
8
+ border: 0.25px solid var(--ifm-color-primary-lightest);
9
+ background-color: var(--ifm-background-color);
10
+ }
@@ -0,0 +1,189 @@
1
+ // src/components/theme/Tabs/index.js
2
+ import React, { cloneElement, useEffect, useRef } from 'react';
3
+ import clsx from 'clsx';
4
+ import {
5
+ useScrollPositionBlocker,
6
+ useTabs,
7
+ } from '@docusaurus/theme-common/internal';
8
+ import useIsBrowser from '@docusaurus/useIsBrowser';
9
+ import styles from './styles.module.css';
10
+
11
+ function TabList({
12
+ className,
13
+ block,
14
+ selectedValue,
15
+ selectValue,
16
+ tabValues,
17
+ queryString,
18
+ }) {
19
+ const tabListRef = useRef(null);
20
+ const tabRefs = [];
21
+ const { blockElementScrollPositionUntilNextRender } =
22
+ useScrollPositionBlocker();
23
+ const isInitialLoad = useRef(true);
24
+
25
+ // Handle initial tab selection from URL and scroll to make tabs visible
26
+ useEffect(() => {
27
+ if (window.location.search && queryString && isInitialLoad.current) {
28
+ const params = new URLSearchParams(window.location.search);
29
+ const parameterName =
30
+ typeof queryString === 'string' ? queryString : 'tabs';
31
+ const queryValue = params.get(parameterName);
32
+
33
+ if (queryValue && queryValue !== selectedValue) {
34
+ selectValue(queryValue);
35
+
36
+ requestAnimationFrame(() => {
37
+ if (tabListRef.current) {
38
+ const headerOffset =
39
+ document.querySelector('header')?.offsetHeight || 0;
40
+ const tabListPosition =
41
+ tabListRef.current.getBoundingClientRect().top + window.scrollY;
42
+
43
+ window.scrollTo({
44
+ top: tabListPosition - headerOffset - 20,
45
+ behavior: 'instant',
46
+ });
47
+ }
48
+ });
49
+
50
+ isInitialLoad.current = false;
51
+ }
52
+ }
53
+ }, [queryString, selectedValue, selectValue, tabValues]);
54
+
55
+ // Handle click events on anchor links
56
+ useEffect(() => {
57
+ const handleClick = (event) => {
58
+ const anchor = event.target.closest('a[href^="#"]');
59
+ if (anchor) {
60
+ // When clicking an anchor link, remove query parameters
61
+ const newUrl = `${window.location.pathname}${anchor.hash}`;
62
+ window.history.pushState({}, '', newUrl);
63
+ }
64
+ };
65
+
66
+ document.addEventListener('click', handleClick);
67
+ return () => document.removeEventListener('click', handleClick);
68
+ }, []);
69
+
70
+ const handleTabChange = (event) => {
71
+ const newTab = event.currentTarget;
72
+ const newTabIndex = tabRefs.indexOf(newTab);
73
+ const newTabValue = tabValues[newTabIndex].value;
74
+
75
+ if (newTabValue !== selectedValue) {
76
+ blockElementScrollPositionUntilNextRender(newTab);
77
+ selectValue(newTabValue);
78
+
79
+ // Always update URL with the tab query parameter
80
+ const parameterName =
81
+ typeof queryString === 'string' ? queryString : 'tabs';
82
+ const newUrl = `${window.location.pathname}?${parameterName}=${newTabValue}${window.location.hash}`;
83
+ window.history.pushState({}, '', newUrl);
84
+ }
85
+ };
86
+
87
+ const handleKeydown = (event) => {
88
+ let focusElement = null;
89
+ switch (event.key) {
90
+ case 'Enter': {
91
+ handleTabChange(event);
92
+ break;
93
+ }
94
+ case 'ArrowRight': {
95
+ const nextTab = tabRefs.indexOf(event.currentTarget) + 1;
96
+ focusElement = tabRefs[nextTab] ?? tabRefs[0];
97
+ break;
98
+ }
99
+ case 'ArrowLeft': {
100
+ const prevTab = tabRefs.indexOf(event.currentTarget) - 1;
101
+ focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1];
102
+ break;
103
+ }
104
+ default:
105
+ break;
106
+ }
107
+ focusElement?.focus();
108
+ };
109
+
110
+ return (
111
+ <ul
112
+ ref={tabListRef}
113
+ role="tablist"
114
+ aria-orientation="horizontal"
115
+ className={clsx(
116
+ 'tabs',
117
+ {
118
+ 'tabs--block': block,
119
+ },
120
+ className,
121
+ styles.roundedTabList
122
+ )}
123
+ >
124
+ {tabValues.map(({ value, label, icon: Icon, attributes }) => (
125
+ <li
126
+ role="tab"
127
+ tabIndex={selectedValue === value ? 0 : -1}
128
+ aria-selected={selectedValue === value}
129
+ key={value}
130
+ ref={(tabControl) => tabRefs.push(tabControl)}
131
+ onKeyDown={handleKeydown}
132
+ onClick={handleTabChange}
133
+ {...attributes}
134
+ className={clsx('tabs__item', styles.tabItem, attributes?.className, {
135
+ 'tabs__item--active': selectedValue === value,
136
+ [styles.activeTabItem]: selectedValue === value,
137
+ })}
138
+ >
139
+ {Icon && <Icon style={{ marginRight: '8px' }} />}
140
+ {label ?? value}
141
+ </li>
142
+ ))}
143
+ </ul>
144
+ );
145
+ }
146
+
147
+ function TabContent({ lazy, children, selectedValue }) {
148
+ const childTabs = (Array.isArray(children) ? children : [children]).filter(
149
+ Boolean
150
+ );
151
+ if (lazy) {
152
+ const selectedTabItem = childTabs.find(
153
+ (tabItem) => tabItem.props.value === selectedValue
154
+ );
155
+ if (!selectedTabItem) {
156
+ return null;
157
+ }
158
+ return cloneElement(selectedTabItem, { className: 'margin-top--sm' });
159
+ }
160
+ return (
161
+ <div>
162
+ {childTabs.map((tabItem, i) =>
163
+ cloneElement(tabItem, {
164
+ key: i,
165
+ hidden: tabItem.props.value !== selectedValue,
166
+ })
167
+ )}
168
+ </div>
169
+ );
170
+ }
171
+
172
+ function TabsComponent(props) {
173
+ const tabs = useTabs(props);
174
+ return (
175
+ <div
176
+ className={clsx('tabs-container', styles.tabList)}
177
+ id={props.queryString}
178
+ >
179
+ <TabList {...props} {...tabs} />
180
+ <TabContent {...props} {...tabs} />
181
+ </div>
182
+ );
183
+ }
184
+
185
+ export default function Tabs(props) {
186
+ const isBrowser = useIsBrowser();
187
+
188
+ return <TabsComponent key={String(isBrowser)} {...props} />;
189
+ }
@@ -0,0 +1,74 @@
1
+ /* styles.module.css */
2
+
3
+ .tabs {
4
+ padding: 0px 0;
5
+ }
6
+
7
+ .tabList {
8
+ margin-bottom: 0;
9
+ }
10
+
11
+ .tabList ul {
12
+ margin-bottom: 0px;
13
+ }
14
+
15
+ .tabList li {
16
+ margin-bottom: 0px;
17
+ }
18
+
19
+ .tabList p {
20
+ margin: 0.75em 0;
21
+ }
22
+
23
+ .tabList h4 {
24
+ margin-top: 1.25em;
25
+ }
26
+
27
+ .tabItem {
28
+ margin-top: 0rem !important;
29
+ font-weight: 600;
30
+ font-size: 17px;
31
+ padding: 0.25rem 0.75rem 0.2rem 0.75rem;
32
+ border-radius: 9999px; /* Fully rounded corners */
33
+ border: none;
34
+ transition:
35
+ background-color 0.05s ease,
36
+ color 0.05s ease,
37
+ box-shadow 0.05s ease;
38
+ cursor: pointer;
39
+ background-color: var(--ifm-background-color);
40
+ }
41
+
42
+ .tabItem:hover {
43
+ background-color: var(--ifm-color-primary-lightest);
44
+ color: #333333;
45
+ }
46
+
47
+ .roundedTabList {
48
+ display: flex;
49
+ gap: 0.45rem;
50
+ flex-wrap: wrap; /* Allow tabs to wrap to the next line */
51
+ }
52
+
53
+ /* Media query to reduce the gap when tabs stack on smaller screens */
54
+ @media (max-width: 768px) {
55
+ .roundedTabList {
56
+ gap: 0.35rem; /* Reduce the gap when stacked on smaller screens */
57
+ }
58
+ }
59
+
60
+ .activeTabItem {
61
+ background-color: var(--ifm-color-primary-darker);
62
+ color: white;
63
+ /* Prevent hover effect on active tab */
64
+ pointer-events: none;
65
+ transition: none;
66
+ }
67
+
68
+ [data-theme='dark'] .activeTabItem {
69
+ color: var(--neutral-slate-900-value, #0f172a);
70
+ }
71
+
72
+ .tabItemContent > *:last-child {
73
+ margin-bottom: 0;
74
+ }
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
2
+ <rect width="32" height="32" rx="6" fill="#7c3aed"/>
3
+ <text x="16" y="22" text-anchor="middle" font-family="system-ui, sans-serif" font-size="18" font-weight="bold" fill="white">D</text>
4
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300">
2
+ <defs>
3
+ <linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" style="stop-color:#7c3aed;stop-opacity:0.1"/>
5
+ <stop offset="100%" style="stop-color:#2dd4bf;stop-opacity:0.1"/>
6
+ </linearGradient>
7
+ </defs>
8
+ <rect width="400" height="300" fill="url(#grad)" rx="20"/>
9
+ <text x="200" y="140" text-anchor="middle" font-family="system-ui" font-size="72" font-weight="700" fill="#7c3aed" opacity="0.3">404</text>
10
+ <text x="200" y="180" text-anchor="middle" font-family="system-ui" font-size="16" fill="#64748b">Page not found</text>
11
+ </svg>
@@ -0,0 +1 @@
1
+ []