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,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,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
|
+
[]
|