mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 07:37:19 +02:00
feat(v2): allow home page for docs (#2652)
* feat(v2): allow home page for docs
* Refactor
* Remove debugging info 🤦♂️
* Add sort routes for first test case
* Sort child routes for consistency
This commit is contained in:
parent
393adc5324
commit
00a8e9e365
12 changed files with 264 additions and 61 deletions
|
@ -52,6 +52,15 @@ Object {
|
|||
|
||||
exports[`simple website content 2`] = `
|
||||
Array [
|
||||
Object {
|
||||
"component": "@theme/DocPage",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/hello.md",
|
||||
"docsMetadata": "~docs/site-docs-hello-md-9df-base.json",
|
||||
},
|
||||
"path": "/docs",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocPage",
|
||||
"modules": Object {
|
||||
|
@ -107,6 +116,33 @@ Array [
|
|||
|
||||
exports[`versioned website content 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"component": "@theme/DocPage",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-1.0.1/hello.md",
|
||||
"docsMetadata": "~docs/site-versioned-docs-version-1-0-1-hello-md-0c7-base.json",
|
||||
},
|
||||
"path": "/docs",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocPage",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-1.0.0/hello.md",
|
||||
"docsMetadata": "~docs/site-versioned-docs-version-1-0-0-hello-md-3ef-base.json",
|
||||
},
|
||||
"path": "/docs/1.0.0",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocPage",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/hello.md",
|
||||
"docsMetadata": "~docs/site-docs-hello-md-9df-base.json",
|
||||
},
|
||||
"path": "/docs/next",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocPage",
|
||||
"modules": Object {
|
||||
|
|
|
@ -93,6 +93,7 @@ describe('simple website', () => {
|
|||
const plugin = pluginContentDocs(context, {
|
||||
path: pluginPath,
|
||||
sidebarPath,
|
||||
homePageId: 'hello',
|
||||
});
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
|
||||
|
@ -203,6 +204,9 @@ describe('simple website', () => {
|
|||
expect(baseMetadata.docsSidebars).toEqual(docsSidebars);
|
||||
expect(baseMetadata.permalinkToSidebar).toEqual(permalinkToSidebar);
|
||||
|
||||
// Sort the route config like in src/server/plugins/index.ts for consistent snapshot ordering
|
||||
sortConfig(routeConfigs);
|
||||
|
||||
expect(routeConfigs).not.toEqual([]);
|
||||
expect(routeConfigs).toMatchSnapshot();
|
||||
});
|
||||
|
@ -216,6 +220,7 @@ describe('versioned website', () => {
|
|||
const plugin = pluginContentDocs(context, {
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
homePageId: 'hello',
|
||||
});
|
||||
const env = loadEnv(siteDir);
|
||||
const {docsDir: versionedDir} = env.versioning;
|
||||
|
|
|
@ -48,9 +48,12 @@ import {Configuration} from 'webpack';
|
|||
import {docsVersion} from './version';
|
||||
import {VERSIONS_JSON_FILE} from './constants';
|
||||
|
||||
const REVERSED_DOCS_HOME_PAGE_ID = '_index';
|
||||
|
||||
const DEFAULT_OPTIONS: PluginOptions = {
|
||||
path: 'docs', // Path to data on filesystem, relative to site dir.
|
||||
routeBasePath: 'docs', // URL Route.
|
||||
homePageId: REVERSED_DOCS_HOME_PAGE_ID, // Document id for docs home page.
|
||||
include: ['**/*.{md,mdx}'], // Extensions to include.
|
||||
sidebarPath: '', // Path to sidebar configuration for showing a list of markdown pages.
|
||||
docLayoutComponent: '@theme/DocPage',
|
||||
|
@ -313,28 +316,96 @@ export default function pluginContentDocs(
|
|||
const aliasedSource = (source: string) =>
|
||||
`~docs/${path.relative(dataDir, source)}`;
|
||||
|
||||
const createDocsBaseMetadata = (version?: string): DocsBaseMetadata => {
|
||||
const {docsSidebars, permalinkToSidebar, versionToSidebars} = content;
|
||||
const neededSidebars: Set<string> =
|
||||
versionToSidebars[version!] || new Set();
|
||||
|
||||
return {
|
||||
docsSidebars: version
|
||||
? pick(docsSidebars, Array.from(neededSidebars))
|
||||
: docsSidebars,
|
||||
permalinkToSidebar: version
|
||||
? pickBy(permalinkToSidebar, (sidebar) =>
|
||||
neededSidebars.has(sidebar),
|
||||
)
|
||||
: permalinkToSidebar,
|
||||
version,
|
||||
};
|
||||
};
|
||||
|
||||
const genRoutes = async (
|
||||
metadataItems: Metadata[],
|
||||
): Promise<RouteConfig[]> => {
|
||||
const routes = await Promise.all(
|
||||
metadataItems.map(async (metadataItem) => {
|
||||
await createData(
|
||||
// Note that this created data path must be in sync with
|
||||
// metadataPath provided to mdx-loader.
|
||||
`${docuHash(metadataItem.source)}.json`,
|
||||
JSON.stringify(metadataItem, null, 2),
|
||||
const routes: RouteConfig[] = [];
|
||||
|
||||
await metadataItems.forEach(async (metadataItem, i) => {
|
||||
const isDocsHomePage =
|
||||
metadataItem.id.substr(metadataItem.id.indexOf('/') + 1) ===
|
||||
options.homePageId;
|
||||
|
||||
if (isDocsHomePage) {
|
||||
const homeDocsRoutePath =
|
||||
routeBasePath === '' ? '/' : routeBasePath;
|
||||
const versionDocsPathPrefix =
|
||||
(metadataItem?.version === versioning.latestVersion
|
||||
? ''
|
||||
: metadataItem.version!) ?? '';
|
||||
|
||||
// To show the sidebar, get the sidebar key of available sibling item.
|
||||
metadataItem.sidebar = (
|
||||
metadataItems[i - 1] ?? metadataItems[i + 1]
|
||||
).sidebar;
|
||||
const docsBaseMetadata = createDocsBaseMetadata(
|
||||
metadataItem.version!,
|
||||
);
|
||||
docsBaseMetadata.isHomePage = true;
|
||||
docsBaseMetadata.homePagePath = normalizeUrl([
|
||||
baseUrl,
|
||||
homeDocsRoutePath,
|
||||
versionDocsPathPrefix,
|
||||
options.homePageId,
|
||||
]);
|
||||
const docsBaseMetadataPath = await createData(
|
||||
`${docuHash(metadataItem.source)}-base.json`,
|
||||
JSON.stringify(docsBaseMetadata, null, 2),
|
||||
);
|
||||
|
||||
return {
|
||||
// Add a route for docs home page.
|
||||
addRoute({
|
||||
path: normalizeUrl([
|
||||
baseUrl,
|
||||
homeDocsRoutePath,
|
||||
versionDocsPathPrefix,
|
||||
]),
|
||||
component: docLayoutComponent,
|
||||
exact: true,
|
||||
modules: {
|
||||
docsMetadata: aliasedSource(docsBaseMetadataPath),
|
||||
content: metadataItem.source,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
await createData(
|
||||
// Note that this created data path must be in sync with
|
||||
// metadataPath provided to mdx-loader.
|
||||
`${docuHash(metadataItem.source)}.json`,
|
||||
JSON.stringify(metadataItem, null, 2),
|
||||
);
|
||||
|
||||
// Do not create a route for a page created specifically for docs home page.
|
||||
if (metadataItem.id !== REVERSED_DOCS_HOME_PAGE_ID) {
|
||||
routes.push({
|
||||
path: metadataItem.permalink,
|
||||
component: docItemComponent,
|
||||
exact: true,
|
||||
modules: {
|
||||
content: metadataItem.source,
|
||||
},
|
||||
};
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return routes.sort((a, b) =>
|
||||
a.path > b.path ? 1 : b.path > a.path ? -1 : 0,
|
||||
|
@ -383,19 +454,7 @@ export default function pluginContentDocs(
|
|||
isLatestVersion ? '' : version,
|
||||
]);
|
||||
const docsBaseRoute = normalizeUrl([docsBasePermalink, ':route']);
|
||||
const neededSidebars: Set<string> =
|
||||
content.versionToSidebars[version] || new Set();
|
||||
const docsBaseMetadata: DocsBaseMetadata = {
|
||||
docsSidebars: pick(
|
||||
content.docsSidebars,
|
||||
Array.from(neededSidebars),
|
||||
),
|
||||
permalinkToSidebar: pickBy(
|
||||
content.permalinkToSidebar,
|
||||
(sidebar) => neededSidebars.has(sidebar),
|
||||
),
|
||||
version,
|
||||
};
|
||||
const docsBaseMetadata = createDocsBaseMetadata(version);
|
||||
|
||||
// We want latest version route config to be placed last in the
|
||||
// generated routeconfig. Otherwise, `/docs/next/foo` will match
|
||||
|
@ -410,16 +469,31 @@ export default function pluginContentDocs(
|
|||
);
|
||||
} else {
|
||||
const routes = await genRoutes(Object.values(content.docsMetadata));
|
||||
const docsBaseMetadata: DocsBaseMetadata = {
|
||||
docsSidebars: content.docsSidebars,
|
||||
permalinkToSidebar: content.permalinkToSidebar,
|
||||
};
|
||||
const docsBaseMetadata = createDocsBaseMetadata();
|
||||
|
||||
const docsBaseRoute = normalizeUrl([baseUrl, routeBasePath, ':route']);
|
||||
return addBaseRoute(docsBaseRoute, docsBaseMetadata, routes);
|
||||
}
|
||||
},
|
||||
|
||||
async routesLoaded(routes) {
|
||||
const normalizedHomeDocsRoutePath = `/${options.routeBasePath}`;
|
||||
const homeDocsRoutes = routes.filter(
|
||||
(routeConfig) => routeConfig.path === normalizedHomeDocsRoutePath,
|
||||
);
|
||||
|
||||
// Remove the route for docs home page if there is a page with the same path (i.e. docs).
|
||||
if (homeDocsRoutes.length > 1) {
|
||||
const docsHomePageRouteIndex = routes.findIndex(
|
||||
(route) =>
|
||||
route.component === options.docLayoutComponent &&
|
||||
route.path === normalizedHomeDocsRoutePath,
|
||||
);
|
||||
|
||||
delete routes[docsHomePageRouteIndex!];
|
||||
}
|
||||
},
|
||||
|
||||
configureWebpack(_config, isServer, utils) {
|
||||
const {getBabelLoader, getCacheLoader} = utils;
|
||||
const {rehypePlugins, remarkPlugins} = options;
|
||||
|
|
|
@ -24,6 +24,7 @@ export interface PluginOptions extends MetadataOptions, PathOptions {
|
|||
remarkPlugins: ([Function, object] | Function)[];
|
||||
rehypePlugins: string[];
|
||||
admonitions: any;
|
||||
homePageId: string;
|
||||
}
|
||||
|
||||
export type SidebarItemDoc = {
|
||||
|
@ -160,6 +161,8 @@ export type DocsBaseMetadata = Pick<
|
|||
'docsSidebars' | 'permalinkToSidebar'
|
||||
> & {
|
||||
version?: string;
|
||||
isHomePage?: boolean;
|
||||
homePagePath?: string;
|
||||
};
|
||||
|
||||
export type VersioningEnv = {
|
||||
|
|
|
@ -11,6 +11,7 @@ import {MDXProvider} from '@mdx-js/react';
|
|||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import renderRoutes from '@docusaurus/renderRoutes';
|
||||
import Layout from '@theme/Layout';
|
||||
import DocItem from '@theme/DocItem';
|
||||
import DocSidebar from '@theme/DocSidebar';
|
||||
import MDXComponents from '@theme/MDXComponents';
|
||||
import NotFound from '@theme/NotFound';
|
||||
|
@ -19,21 +20,31 @@ import {matchPath} from '@docusaurus/router';
|
|||
import styles from './styles.module.css';
|
||||
|
||||
function DocPage(props) {
|
||||
const {route: baseRoute, docsMetadata, location} = props;
|
||||
// case-sensitive route such as it is defined in the sidebar
|
||||
const currentRoute =
|
||||
baseRoute.routes.find((route) => {
|
||||
return matchPath(location.pathname, route);
|
||||
}) || {};
|
||||
const {permalinkToSidebar, docsSidebars, version} = docsMetadata;
|
||||
const sidebar = permalinkToSidebar[currentRoute.path];
|
||||
const {route: baseRoute, docsMetadata, location, content} = props;
|
||||
const {
|
||||
siteConfig: {themeConfig = {}} = {},
|
||||
permalinkToSidebar,
|
||||
docsSidebars,
|
||||
version,
|
||||
isHomePage,
|
||||
homePagePath,
|
||||
} = docsMetadata;
|
||||
|
||||
// Get case-sensitive route such as it is defined in the sidebar.
|
||||
const currentRoute = !isHomePage
|
||||
? baseRoute.routes.find((route) => {
|
||||
return matchPath(location.pathname, route);
|
||||
}) || {}
|
||||
: {};
|
||||
|
||||
const sidebar = isHomePage
|
||||
? content.metadata.sidebar
|
||||
: permalinkToSidebar[currentRoute.path];
|
||||
const {
|
||||
siteConfig: {themeConfig: {sidebarCollapsible = true} = {}} = {},
|
||||
isClient,
|
||||
} = useDocusaurusContext();
|
||||
const {sidebarCollapsible = true} = themeConfig;
|
||||
|
||||
if (Object.keys(currentRoute).length === 0) {
|
||||
if (!isHomePage && Object.keys(currentRoute).length === 0) {
|
||||
return <NotFound {...props} />;
|
||||
}
|
||||
|
||||
|
@ -44,7 +55,7 @@ function DocPage(props) {
|
|||
<div className={styles.docSidebarContainer}>
|
||||
<DocSidebar
|
||||
docsSidebars={docsSidebars}
|
||||
path={currentRoute.path}
|
||||
path={isHomePage ? homePagePath : currentRoute.path}
|
||||
sidebar={sidebar}
|
||||
sidebarCollapsible={sidebarCollapsible}
|
||||
/>
|
||||
|
@ -52,7 +63,11 @@ function DocPage(props) {
|
|||
)}
|
||||
<main className={styles.docMainContainer}>
|
||||
<MDXProvider components={MDXComponents}>
|
||||
{renderRoutes(baseRoute.routes)}
|
||||
{isHomePage ? (
|
||||
<DocItem content={content} />
|
||||
) : (
|
||||
renderRoutes(baseRoute.routes)
|
||||
)}
|
||||
</MDXProvider>
|
||||
</main>
|
||||
</div>
|
||||
|
|
|
@ -17,7 +17,13 @@ import styles from './styles.module.css';
|
|||
|
||||
const MOBILE_TOGGLE_SIZE = 24;
|
||||
|
||||
function DocSidebarItem({item, onItemClick, collapsible, ...props}) {
|
||||
function DocSidebarItem({
|
||||
item,
|
||||
onItemClick,
|
||||
collapsible,
|
||||
activePath,
|
||||
...props
|
||||
}) {
|
||||
const {items, href, label, type} = item;
|
||||
const [collapsed, setCollapsed] = useState(item.collapsed);
|
||||
const [prevCollapsedProp, setPreviousCollapsedProp] = useState(null);
|
||||
|
@ -63,6 +69,7 @@ function DocSidebarItem({item, onItemClick, collapsible, ...props}) {
|
|||
item={childItem}
|
||||
onItemClick={onItemClick}
|
||||
collapsible={collapsible}
|
||||
activePath={activePath}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
|
@ -75,7 +82,9 @@ function DocSidebarItem({item, onItemClick, collapsible, ...props}) {
|
|||
return (
|
||||
<li className="menu__list-item" key={label}>
|
||||
<Link
|
||||
className="menu__link"
|
||||
className={classnames('menu__link', {
|
||||
'menu__link--active': href === activePath,
|
||||
})}
|
||||
to={href}
|
||||
{...(isInternalUrl(href)
|
||||
? {
|
||||
|
@ -219,6 +228,7 @@ function DocSidebar(props) {
|
|||
setShowResponsiveSidebar(false);
|
||||
}}
|
||||
collapsible={sidebarCollapsible}
|
||||
activePath={path}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
|
|
1
packages/docusaurus-types/src/index.d.ts
vendored
1
packages/docusaurus-types/src/index.d.ts
vendored
|
@ -105,6 +105,7 @@ export interface Plugin<T> {
|
|||
content: T;
|
||||
actions: PluginContentLoadedActions;
|
||||
}): void;
|
||||
routesLoaded?(routes: RouteConfig[]): void;
|
||||
postBuild?(props: Props): void;
|
||||
postStart?(props: Props): void;
|
||||
configureWebpack?(
|
||||
|
|
|
@ -40,6 +40,12 @@ export function sortConfig(routeConfigs: RouteConfig[]) {
|
|||
|
||||
return a.path > b.path ? 1 : b.path > a.path ? -1 : 0;
|
||||
});
|
||||
|
||||
routeConfigs.forEach((routeConfig) => {
|
||||
routeConfig.routes?.sort((a, b) => {
|
||||
return a.path > b.path ? 1 : b.path > a.path ? -1 : 0;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function loadPlugins({
|
||||
|
@ -100,6 +106,20 @@ export async function loadPlugins({
|
|||
}),
|
||||
);
|
||||
|
||||
// 4. Plugin Lifecycle - routesLoaded.
|
||||
// Currently plugins run lifecycle methods in parallel and are not order-dependent.
|
||||
// We could change this in future if there are plugins which need to
|
||||
// run in certain order or depend on others for data.
|
||||
await Promise.all(
|
||||
plugins.map(async (plugin) => {
|
||||
if (!plugin.routesLoaded) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await plugin.routesLoaded(pluginsRouteConfigs);
|
||||
}),
|
||||
);
|
||||
|
||||
// Sort the route config. This ensures that route with nested
|
||||
// routes are always placed last.
|
||||
sortConfig(pluginsRouteConfigs);
|
||||
|
|
|
@ -29,6 +29,42 @@ id: part1
|
|||
Lorem ipsum
|
||||
```
|
||||
|
||||
## Home page docs
|
||||
|
||||
Using the `homePageId` property, you can create a home page of your docs. To do this, you can create a new document, especially for this purpose with the id as `_index`, or you could specify an existing document id.
|
||||
|
||||
```js {8} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
homePageId: 'getting-started', // Defaults to `_index`
|
||||
// ...
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
Given the example above, now when you navigate to the path `/docs` you will see that the document content with id is `getting-started`. This functionality also works for docs with versioning enabled.
|
||||
|
||||
:::important
|
||||
|
||||
The document id of `_index` is reserved exclusively for the home doc page, so it will not work as a standalone route.
|
||||
|
||||
:::
|
||||
|
||||
:::note
|
||||
|
||||
The page `docs` that you created (eg. `src/pages/docs.js`) will take precedence over the route generated via the `homePageId` option.
|
||||
|
||||
:::
|
||||
|
||||
## Sidebar
|
||||
|
||||
To generate a sidebar to your Docusaurus site, you need to define a file that exports a sidebar object and pass that into the `@docusaurus/plugin-docs` plugin directly or via `@docusaurus/preset-classic`.
|
||||
|
@ -258,11 +294,17 @@ module.exports = {
|
|||
|
||||
## Docs-only mode
|
||||
|
||||
If you just want the documentation feature, you can follow the instructions for a "docs-only mode":
|
||||
If you just want the documentation feature, you can enable "docs-only mode".
|
||||
|
||||
1. Set the `routeBasePath` property of the `docs` object in `@docusaurus/preset-classic` in `docusaurus.config.js` to the root of your site:
|
||||
To achieve this, set the `routeBasePath` property of the `docs` object in `@docusaurus/preset-classic` in `docusaurus.config.js` to the root of your site, and also in that object set the `homePageId` property with the value of the document ID that you show as root of the docs.
|
||||
|
||||
```js {8} title="docusaurus.config.js"
|
||||
:::note
|
||||
|
||||
More details on functionality of home page for docs can be found in [appropriate section](#home-page-docs).
|
||||
|
||||
:::
|
||||
|
||||
```js {8-9} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
presets: [
|
||||
|
@ -271,6 +313,7 @@ module.exports = {
|
|||
{
|
||||
docs: {
|
||||
routeBasePath: '/', // Set this value to '/'.
|
||||
homePageId: 'getting-started', // Set to existing document id.
|
||||
// ...
|
||||
},
|
||||
},
|
||||
|
@ -280,21 +323,6 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
2. Set up a redirect to the initial document on the home page in `/src/pages/index.js`, e.g. for the document `getting-started`. This is needed because by default there's no page created for the root of the docs.
|
||||
|
||||
```jsx title="src/pages/index.js"
|
||||
import React from 'react';
|
||||
|
||||
import {Redirect} from '@docusaurus/router';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
function Home() {
|
||||
return <Redirect to={useBaseUrl('/getting-started')} />;
|
||||
}
|
||||
|
||||
export default Home;
|
||||
```
|
||||
|
||||
Now, when visiting your site, it will show your initial document instead of a landing page.
|
||||
|
||||
:::tip
|
||||
|
|
|
@ -52,6 +52,10 @@ module.exports = function (context, options) {
|
|||
|
||||
Plugins should use the data loaded in `loadContent` and construct the pages/routes that consume the loaded data (optional).
|
||||
|
||||
## `async routesLoaded(routes)`
|
||||
|
||||
Plugins can modify the routes that were generated by all plugins. `routesLoaded` is called after `contentLoaded` hook.
|
||||
|
||||
### `content`
|
||||
|
||||
`contentLoaded` will be called _after_ `loadContent` is done, the return value of `loadContent()` will be passed to `contentLoaded` as `content`.
|
||||
|
@ -373,6 +377,11 @@ module.exports = function (context, opts) {
|
|||
// actions are set of functional API provided by Docusaurus. e.g: addRoute
|
||||
},
|
||||
|
||||
async routesLoaded(routes) {
|
||||
// routesLoaded hook is done after contentLoaded hook is done
|
||||
// This can be useful if you need to change any route.
|
||||
},
|
||||
|
||||
async postBuild(props) {
|
||||
// after docusaurus <build> finish
|
||||
},
|
||||
|
|
|
@ -236,6 +236,7 @@ module.exports = {
|
|||
* do not include trailing slash
|
||||
*/
|
||||
routeBasePath: 'docs',
|
||||
homePageId: '_index', // Document id for docs home page.
|
||||
include: ['**/*.md', '**/*.mdx'], // Extensions to include.
|
||||
/**
|
||||
* Path to sidebar configuration for showing a list of markdown pages.
|
||||
|
|
|
@ -36,6 +36,7 @@ module.exports = {
|
|||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
homePageId: 'introduction',
|
||||
path: 'docs',
|
||||
sidebarPath: require.resolve('./sidebars.js'),
|
||||
editUrl:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue