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,200 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import {themes as prismThemes} from 'prism-react-renderer';
|
|
3
|
+
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
/** @type {import('@docusaurus/types').Config} */
|
|
7
|
+
const config = {
|
|
8
|
+
title: "{{projectName}}",
|
|
9
|
+
tagline: "{{tagline}}",
|
|
10
|
+
url: "{{siteUrl}}",
|
|
11
|
+
baseUrl: "/",
|
|
12
|
+
trailingSlash: true,
|
|
13
|
+
onBrokenLinks: "warn",
|
|
14
|
+
onBrokenMarkdownLinks: "warn",
|
|
15
|
+
favicon: "img/favicon.svg",
|
|
16
|
+
organizationName: "",
|
|
17
|
+
projectName: "{{projectSlug}}",
|
|
18
|
+
|
|
19
|
+
customFields: {
|
|
20
|
+
repoUrl: '{{repoUrl}}',
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
markdown: {
|
|
24
|
+
mermaid: true,
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
themes: [
|
|
28
|
+
'@docusaurus/theme-mermaid',
|
|
29
|
+
'@docusaurus/theme-live-codeblock',
|
|
30
|
+
],
|
|
31
|
+
|
|
32
|
+
staticDirectories: ['static'],
|
|
33
|
+
|
|
34
|
+
i18n: {
|
|
35
|
+
defaultLocale: 'en',
|
|
36
|
+
locales: ['en'],
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
presets: [
|
|
40
|
+
[
|
|
41
|
+
'classic',
|
|
42
|
+
/** @type {import('@docusaurus/preset-classic').Options} */
|
|
43
|
+
({
|
|
44
|
+
docs: {
|
|
45
|
+
breadcrumbs: true,
|
|
46
|
+
sidebarPath: './sidebars.js',
|
|
47
|
+
routeBasePath: '/',
|
|
48
|
+
path: 'docs',
|
|
49
|
+
showLastUpdateTime: true,
|
|
50
|
+
editUrl: '{{repoUrl}}/edit/main',
|
|
51
|
+
},
|
|
52
|
+
blog: {
|
|
53
|
+
showReadingTime: false,
|
|
54
|
+
},
|
|
55
|
+
theme: {
|
|
56
|
+
customCss: [
|
|
57
|
+
'./src/css/tokens.css',
|
|
58
|
+
'./src/css/custom.css',
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
}),
|
|
62
|
+
],
|
|
63
|
+
],
|
|
64
|
+
|
|
65
|
+
plugins: [
|
|
66
|
+
'@r74tech/docusaurus-plugin-panzoom',
|
|
67
|
+
[
|
|
68
|
+
'./packages/faq-index-plugin',
|
|
69
|
+
{
|
|
70
|
+
faqDir: 'docs/faq',
|
|
71
|
+
basePermalink: '/faq',
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
function webpackPlugin(context, options) {
|
|
75
|
+
return {
|
|
76
|
+
name: 'webpack-config-plugin',
|
|
77
|
+
configureWebpack(config, isServer, utils) {
|
|
78
|
+
return {
|
|
79
|
+
resolve: {
|
|
80
|
+
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
|
|
81
|
+
extensionAlias: {
|
|
82
|
+
'.js': ['.js', '.jsx'],
|
|
83
|
+
'.mjs': ['.mjs', '.mjs'],
|
|
84
|
+
'.cjs': ['.cjs', '.cjs'],
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
[
|
|
92
|
+
'redirects-plugin',
|
|
93
|
+
{
|
|
94
|
+
redirectsFile: 'redirects.json'
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
[
|
|
98
|
+
'smart-search-plugin',
|
|
99
|
+
{
|
|
100
|
+
excludedFolders: ['includes', '_includes'],
|
|
101
|
+
excludedPrefixes: ['_'],
|
|
102
|
+
searchWeights: {
|
|
103
|
+
title: 1.0,
|
|
104
|
+
'sections.heading': 1.0,
|
|
105
|
+
keywords: 0.8,
|
|
106
|
+
description: 0.6,
|
|
107
|
+
'sections.content': 0.5,
|
|
108
|
+
content: 0.4
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
[
|
|
113
|
+
'lightbox-image-plugin',
|
|
114
|
+
{
|
|
115
|
+
selector: '.markdown img',
|
|
116
|
+
background: 'rgba(0, 0, 0, 0.8)',
|
|
117
|
+
zIndex: 999,
|
|
118
|
+
margin: 10,
|
|
119
|
+
scrollOffset: 10
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
],
|
|
123
|
+
|
|
124
|
+
themeConfig:
|
|
125
|
+
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
|
|
126
|
+
({
|
|
127
|
+
docs: {
|
|
128
|
+
sidebar: {
|
|
129
|
+
hideable: true,
|
|
130
|
+
autoCollapseCategories: false,
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
colorMode: {
|
|
134
|
+
defaultMode: 'dark',
|
|
135
|
+
disableSwitch: false,
|
|
136
|
+
respectPrefersColorScheme: true,
|
|
137
|
+
},
|
|
138
|
+
zoom: {
|
|
139
|
+
selectors: ['div.mermaid[data-processed="true"]', 'div.docusaurus-mermaid-container', '.drawio'],
|
|
140
|
+
wrap: true,
|
|
141
|
+
timeout: 1000,
|
|
142
|
+
toolbar: {
|
|
143
|
+
enabled: true,
|
|
144
|
+
position: 'top-right',
|
|
145
|
+
opacity: 0,
|
|
146
|
+
},
|
|
147
|
+
enableWheelZoom: true,
|
|
148
|
+
enableWheelZoomWithShift: false,
|
|
149
|
+
enableDoubleClickResetZoom: true,
|
|
150
|
+
restrictZoomOutBeyondOrigin: false,
|
|
151
|
+
},
|
|
152
|
+
metadata: [
|
|
153
|
+
{ property: 'og:description', content: '{{projectName}} — {{tagline}}' },
|
|
154
|
+
],
|
|
155
|
+
navbar: {
|
|
156
|
+
title: '{{projectName}}',
|
|
157
|
+
logo: {
|
|
158
|
+
alt: '{{projectName}} Logo',
|
|
159
|
+
src: 'img/favicon.svg',
|
|
160
|
+
className: 'header-logo',
|
|
161
|
+
},
|
|
162
|
+
items: [
|
|
163
|
+
{
|
|
164
|
+
to: '/guides/writing-docs',
|
|
165
|
+
label: 'Guides',
|
|
166
|
+
position: 'right',
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
type: 'dropdown',
|
|
170
|
+
label: 'Resources',
|
|
171
|
+
position: 'right',
|
|
172
|
+
items: [
|
|
173
|
+
{
|
|
174
|
+
to: '/blog',
|
|
175
|
+
label: 'Release Notes',
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
to: '/faq',
|
|
179
|
+
label: 'FAQs',
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
type: 'search',
|
|
185
|
+
position: 'right',
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
},
|
|
189
|
+
footer: {
|
|
190
|
+
style: 'dark',
|
|
191
|
+
copyright: `\u00a9 ${new Date().getFullYear()} {{projectName}} | Powered by Trellis`,
|
|
192
|
+
},
|
|
193
|
+
prism: {
|
|
194
|
+
theme: prismThemes.github,
|
|
195
|
+
darkTheme: prismThemes.dracula,
|
|
196
|
+
},
|
|
197
|
+
}),
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
export default config;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectSlug}}",
|
|
3
|
+
"license": "MIT",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"private": true,
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build-tokens": "node scripts/build-tokens.js",
|
|
8
|
+
"docusaurus": "npm run build-tokens && docusaurus",
|
|
9
|
+
"start": "npm run build-tokens && docusaurus start --port 3001",
|
|
10
|
+
"build": "npm run build-tokens && docusaurus build",
|
|
11
|
+
"serve": "docusaurus serve",
|
|
12
|
+
"clear": "docusaurus clear"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@ant-design/icons": "^5.3.7",
|
|
16
|
+
"@docusaurus/core": "^3.9.2",
|
|
17
|
+
"@docusaurus/mdx-loader": "^3.9.2",
|
|
18
|
+
"@docusaurus/preset-classic": "^3.9.2",
|
|
19
|
+
"@docusaurus/theme-live-codeblock": "^3.9.2",
|
|
20
|
+
"@docusaurus/theme-mermaid": "3.9.2",
|
|
21
|
+
"@emotion/react": "^11.13.3",
|
|
22
|
+
"@emotion/styled": "^11.13.0",
|
|
23
|
+
"@mdx-js/react": "^3.1.1",
|
|
24
|
+
"@mermaid-js/layout-elk": "^0.1.9",
|
|
25
|
+
"@mui/icons-material": "^5.10.6",
|
|
26
|
+
"@mui/material": "^5.16.4",
|
|
27
|
+
"@r74tech/docusaurus-plugin-panzoom": "^2.4.0",
|
|
28
|
+
"antd": "^5.27.3",
|
|
29
|
+
"clsx": "^2.0.0",
|
|
30
|
+
"fuse.js": "^7.1.0",
|
|
31
|
+
"gray-matter": "^4.0.3",
|
|
32
|
+
"lightbox-image-plugin": "^1.0.1",
|
|
33
|
+
"mermaid": "^11.11.0",
|
|
34
|
+
"prism-react-renderer": "^2.4.1",
|
|
35
|
+
"react": "^19.0.0",
|
|
36
|
+
"react-dom": "^19.0.0",
|
|
37
|
+
"react-router-dom": "^5.3.4",
|
|
38
|
+
"redirects-plugin": "file:./packages/redirects-plugin",
|
|
39
|
+
"docusaurus-plugin-faq-index": "file:./packages/faq-index-plugin",
|
|
40
|
+
"smart-search-plugin": "^3.1.1",
|
|
41
|
+
"webpack": "^5.104.1",
|
|
42
|
+
"yaml": "^2.8.1"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@docusaurus/module-type-aliases": "3.9.2",
|
|
46
|
+
"@docusaurus/types": "3.9.2"
|
|
47
|
+
},
|
|
48
|
+
"browserslist": {
|
|
49
|
+
"production": [
|
|
50
|
+
">0.5%",
|
|
51
|
+
"not dead",
|
|
52
|
+
"not op_mini all"
|
|
53
|
+
],
|
|
54
|
+
"development": [
|
|
55
|
+
"last 3 chrome version",
|
|
56
|
+
"last 3 firefox version",
|
|
57
|
+
"last 5 safari version"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# FAQ Index Plugin for Docusaurus
|
|
2
|
+
|
|
3
|
+
A Docusaurus 3.x local plugin that scans `/docs/faq/*.mdx` at build time, extracts questions from `###` headings, and exposes the full FAQ index via `setGlobalData`. Designed to work with the `FaqTableOfContents` component.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔍 Auto-discovery of FAQ files in `docs/faq/`
|
|
8
|
+
- 📋 Extracts questions from `###` headings with frontmatter parsing
|
|
9
|
+
- 🔗 Generates deep-link anchors matching Docusaurus conventions
|
|
10
|
+
- 📦 Exposes data via `useGlobalData` for client-side components
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
This is a local plugin included in the project under `packages/`. No separate installation is needed, but ensure `gray-matter` is available:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
cd packages/faq-index-plugin
|
|
18
|
+
yarn install
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Configuration
|
|
22
|
+
|
|
23
|
+
Add the plugin to `docusaurus.config.js`:
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
module.exports = {
|
|
27
|
+
plugins: [
|
|
28
|
+
[
|
|
29
|
+
'./packages/faq-index-plugin',
|
|
30
|
+
{
|
|
31
|
+
faqDir: 'docs/faq', // path relative to site root
|
|
32
|
+
basePermalink: '/faq', // base URL path for FAQ pages
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Plugin options
|
|
40
|
+
|
|
41
|
+
| Option | Type | Default | Description |
|
|
42
|
+
|-----------------|----------|--------------|--------------------------------------------------|
|
|
43
|
+
| `faqDir` | `string` | `'docs/faq'` | Path to the FAQ folder relative to the site root. |
|
|
44
|
+
| `basePermalink` | `string` | `'/faq'` | Base permalink for generated FAQ links. |
|
|
45
|
+
|
|
46
|
+
## How it works
|
|
47
|
+
|
|
48
|
+
1. At build time, the plugin reads every `.mdx` and `.md` file in the configured FAQ directory (excluding `index.mdx` and `index.md`).
|
|
49
|
+
2. It parses each file's frontmatter for `title` and `description` using `gray-matter`.
|
|
50
|
+
3. It extracts question text from every `###` heading, stripping bold, italic, inline code, and link formatting.
|
|
51
|
+
4. The full index is sorted alphabetically by topic title and exposed via Docusaurus `setGlobalData`.
|
|
52
|
+
5. The `FaqTableOfContents` component reads this data at runtime using `useGlobalData`.
|
|
53
|
+
|
|
54
|
+
## Expected FAQ file format
|
|
55
|
+
|
|
56
|
+
Each topic file should use `###` headings for questions:
|
|
57
|
+
|
|
58
|
+
```mdx
|
|
59
|
+
---
|
|
60
|
+
title: Secrets
|
|
61
|
+
description: Managing secrets, vaults, and credential rotation.
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
# Secrets
|
|
65
|
+
|
|
66
|
+
### How do I add a secret to my application?
|
|
67
|
+
|
|
68
|
+
Answer content here...
|
|
69
|
+
|
|
70
|
+
### How do I rotate a secret?
|
|
71
|
+
|
|
72
|
+
Answer content here...
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Anchor generation
|
|
76
|
+
|
|
77
|
+
The plugin generates anchors from heading text using the same convention as Docusaurus: lowercase, special characters stripped, spaces replaced with hyphens. Deep links align automatically with Docusaurus-rendered anchors unless you use custom heading IDs (e.g., `### My heading {#custom-id}`).
|
|
78
|
+
|
|
79
|
+
## File structure
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
your-docusaurus-project/
|
|
83
|
+
├── docs/
|
|
84
|
+
│ └── faq/
|
|
85
|
+
│ ├── index.mdx
|
|
86
|
+
│ ├── authentication-permissions.mdx
|
|
87
|
+
│ ├── database-infrastructure.mdx
|
|
88
|
+
│ └── secrets.mdx
|
|
89
|
+
├── packages/
|
|
90
|
+
│ └── faq-index-plugin/
|
|
91
|
+
│ ├── package.json
|
|
92
|
+
│ ├── index.js
|
|
93
|
+
│ └── README.md
|
|
94
|
+
├── src/
|
|
95
|
+
│ └── components/
|
|
96
|
+
│ └── FaqTableOfContents/
|
|
97
|
+
│ ├── index.jsx
|
|
98
|
+
│ └── styles.module.css
|
|
99
|
+
└── docusaurus.config.js
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
MIT
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// packages/faq-index-plugin/index.js
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const matter = require('gray-matter');
|
|
6
|
+
|
|
7
|
+
const PLUGIN_NAME = 'docusaurus-plugin-faq-index';
|
|
8
|
+
|
|
9
|
+
module.exports = function faqIndexPlugin(context, options) {
|
|
10
|
+
const opts = options || {};
|
|
11
|
+
const faqDir = path.resolve(context.siteDir, opts.faqDir || 'docs/faq');
|
|
12
|
+
const basePermalink = opts.basePermalink || '/faq';
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
name: PLUGIN_NAME,
|
|
16
|
+
|
|
17
|
+
async loadContent() {
|
|
18
|
+
if (!fs.existsSync(faqDir)) {
|
|
19
|
+
console.warn(`[${PLUGIN_NAME}] FAQ directory not found: ${faqDir}`);
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const files = fs
|
|
24
|
+
.readdirSync(faqDir)
|
|
25
|
+
.filter((f) => /\.(mdx?)$/.test(f) && f !== 'index.mdx' && f !== 'index.md');
|
|
26
|
+
|
|
27
|
+
const topics = [];
|
|
28
|
+
|
|
29
|
+
for (const file of files) {
|
|
30
|
+
const filePath = path.join(faqDir, file);
|
|
31
|
+
|
|
32
|
+
let raw;
|
|
33
|
+
try {
|
|
34
|
+
raw = fs.readFileSync(filePath, 'utf-8');
|
|
35
|
+
} catch (err) {
|
|
36
|
+
console.warn(`[${PLUGIN_NAME}] Could not read ${filePath}:`, err.message);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const { data: frontmatter, content } = matter(raw);
|
|
41
|
+
|
|
42
|
+
const slug = file.replace(/\.mdx?$/, '');
|
|
43
|
+
const title =
|
|
44
|
+
frontmatter.title ||
|
|
45
|
+
slug
|
|
46
|
+
.replace(/-/g, ' ')
|
|
47
|
+
.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
48
|
+
|
|
49
|
+
// Extract questions from ### headings
|
|
50
|
+
const h3Regex = /^###\s+(.+)$/gm;
|
|
51
|
+
const questions = [];
|
|
52
|
+
let match;
|
|
53
|
+
|
|
54
|
+
while ((match = h3Regex.exec(content)) !== null) {
|
|
55
|
+
let questionText = match[1]
|
|
56
|
+
.trim()
|
|
57
|
+
.replace(/\*{1,3}(.*?)\*{1,3}/g, '$1')
|
|
58
|
+
.replace(/`([^`]+)`/g, '$1')
|
|
59
|
+
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
|
|
60
|
+
.trim();
|
|
61
|
+
|
|
62
|
+
if (questionText) {
|
|
63
|
+
const anchor = questionText
|
|
64
|
+
.toLowerCase()
|
|
65
|
+
.replace(/[^\w\s-]/g, '')
|
|
66
|
+
.replace(/\s+/g, '-')
|
|
67
|
+
.replace(/-+/g, '-');
|
|
68
|
+
|
|
69
|
+
questions.push({ text: questionText, anchor });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
topics.push({
|
|
74
|
+
slug,
|
|
75
|
+
title,
|
|
76
|
+
description: frontmatter.description || '',
|
|
77
|
+
permalink: `${basePermalink}/${slug}`,
|
|
78
|
+
questions,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
topics.sort((a, b) => a.title.localeCompare(b.title));
|
|
83
|
+
return topics;
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
async contentLoaded({ content, actions }) {
|
|
87
|
+
const { setGlobalData } = actions;
|
|
88
|
+
setGlobalData({ topics: content || [] });
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "faq-index-plugin",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A custom Docusaurus plugin that indexes FAQ questions from docs/faq/ at build time",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"author": "Patricia McPhee",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"peerDependencies": {
|
|
9
|
+
"@docusaurus/core": "3.9.2",
|
|
10
|
+
"react": "^19.0.0"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"gray-matter": "^4.0.3"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Redirects Plugin for Docusaurus
|
|
2
|
+
|
|
3
|
+
A Docusaurus 3.x plugin that handles URL redirects by generating static HTML redirect pages during the build process.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔄 Create client-side redirects using meta refresh and JavaScript
|
|
8
|
+
- 📁 Support for multiple redirect configuration sources
|
|
9
|
+
- 🎯 Handles both file-based (`/path.html`) and directory-based (`/path/index.html`) redirects
|
|
10
|
+
- 🔍 Auto-detection of redirect configuration files
|
|
11
|
+
- ⚡ Zero runtime overhead - generates static HTML files
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
This is a local plugin included in the project. No separate installation needed.
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
Add the plugin to your `docusaurus.config.js`:
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
module.exports = {
|
|
23
|
+
plugins: [
|
|
24
|
+
[
|
|
25
|
+
'./packages/redirects-plugin',
|
|
26
|
+
{
|
|
27
|
+
// Optional: specify redirects directly in config
|
|
28
|
+
redirects: [
|
|
29
|
+
{
|
|
30
|
+
from: '/old-page',
|
|
31
|
+
to: '/new-page',
|
|
32
|
+
type: 301 // optional, defaults to 301
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
// Optional: specify a custom redirects file location
|
|
36
|
+
redirectsFile: 'config/redirects.json'
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
]
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Redirect Configuration Sources
|
|
44
|
+
|
|
45
|
+
The plugin loads redirects from multiple sources in this order:
|
|
46
|
+
|
|
47
|
+
### 1. Plugin Options
|
|
48
|
+
|
|
49
|
+
Define redirects directly in `docusaurus.config.js`:
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
{
|
|
53
|
+
redirects: [
|
|
54
|
+
{ from: '/old', to: '/new' },
|
|
55
|
+
{ from: '/legacy/path', to: '/modern/path', type: 302 }
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 2. Custom File Location
|
|
61
|
+
|
|
62
|
+
Specify a custom file path:
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
{
|
|
66
|
+
redirectsFile: 'config/my-redirects.json'
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 3. Auto-Detection
|
|
71
|
+
|
|
72
|
+
If no `redirectsFile` is specified, the plugin automatically looks for:
|
|
73
|
+
|
|
74
|
+
- `redirects.json` (project root)
|
|
75
|
+
- `config/redirects.json`
|
|
76
|
+
- `src/redirects.json`
|
|
77
|
+
|
|
78
|
+
## Redirects File Format
|
|
79
|
+
|
|
80
|
+
Create a `redirects.json` file:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
[
|
|
84
|
+
{
|
|
85
|
+
"from": "/old-docs/getting-started",
|
|
86
|
+
"to": "/docs/introduction"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"from": "/api-v1",
|
|
90
|
+
"to": "/api/v2",
|
|
91
|
+
"type": 302
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"from": "/blog/old-post",
|
|
95
|
+
"to": "https://external-site.com/new-post"
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Redirect Object Properties
|
|
101
|
+
|
|
102
|
+
| Property | Type | Required | Default | Description |
|
|
103
|
+
|----------|------|----------|---------|-------------|
|
|
104
|
+
| `from` | string | Yes | - | Source path to redirect from |
|
|
105
|
+
| `to` | string | Yes | - | Destination URL or path |
|
|
106
|
+
| `type` | number | No | 301 | HTTP redirect status code |
|
|
107
|
+
|
|
108
|
+
## How It Works
|
|
109
|
+
|
|
110
|
+
1. During the build process, the plugin reads all configured redirects
|
|
111
|
+
2. For each redirect, it generates HTML files with:
|
|
112
|
+
- Meta refresh tag for immediate redirect
|
|
113
|
+
- JavaScript fallback for better compatibility
|
|
114
|
+
- Canonical link tag for SEO
|
|
115
|
+
3. Creates both `/path.html` and `/path/index.html` for maximum compatibility
|
|
116
|
+
|
|
117
|
+
## Generated HTML Example
|
|
118
|
+
|
|
119
|
+
For a redirect from `/old` to `/new`, the plugin generates:
|
|
120
|
+
|
|
121
|
+
```html
|
|
122
|
+
<!DOCTYPE html>
|
|
123
|
+
<html>
|
|
124
|
+
<head>
|
|
125
|
+
<meta charset="UTF-8">
|
|
126
|
+
<meta http-equiv="refresh" content="0; url=/new">
|
|
127
|
+
<link rel="canonical" href="/new" />
|
|
128
|
+
<title>Redirecting...</title>
|
|
129
|
+
</head>
|
|
130
|
+
<body>
|
|
131
|
+
<p>Redirecting to <a href="/new">/new</a>...</p>
|
|
132
|
+
<script>
|
|
133
|
+
window.location.href = '/new';
|
|
134
|
+
</script>
|
|
135
|
+
</body>
|
|
136
|
+
</html>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Path Normalization
|
|
140
|
+
|
|
141
|
+
- Leading slashes are added if missing
|
|
142
|
+
- Trailing slashes are removed for consistency
|
|
143
|
+
- Hash fragments are preserved
|
|
144
|
+
- External URLs (starting with `http`) are supported
|
|
145
|
+
|
|
146
|
+
## Debugging
|
|
147
|
+
|
|
148
|
+
The plugin logs its activity during the build:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
Loaded 5 redirects from config
|
|
152
|
+
Auto-detected and loaded 10 redirects from redirects.json
|
|
153
|
+
Processing 15 redirects...
|
|
154
|
+
Created redirect: /old → /new (301)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Common Use Cases
|
|
158
|
+
|
|
159
|
+
- Maintaining URLs after site restructuring
|
|
160
|
+
- Redirecting from legacy documentation versions
|
|
161
|
+
- Creating short URLs for marketing campaigns
|
|
162
|
+
- Handling moved or renamed pages
|
|
163
|
+
- Redirecting to external resources
|
|
164
|
+
|
|
165
|
+
## Limitations
|
|
166
|
+
|
|
167
|
+
- Redirects only work for paths that don't correspond to actual files
|
|
168
|
+
- Server-side redirects are more efficient but require server configuration
|
|
169
|
+
- Meta refresh redirects may not preserve HTTP referrer information
|
|
170
|
+
|
|
171
|
+
## Troubleshooting
|
|
172
|
+
|
|
173
|
+
**Redirects not working:**
|
|
174
|
+
|
|
175
|
+
- Check that the source path doesn't conflict with an existing page
|
|
176
|
+
- Verify the JSON file is valid (use a JSON validator)
|
|
177
|
+
- Check build logs for error messages
|
|
178
|
+
|
|
179
|
+
**Invalid redirect warnings:**
|
|
180
|
+
|
|
181
|
+
- Ensure both `from` and `to` fields are present
|
|
182
|
+
- Check for typos in field names
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
MIT
|