mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 15:47:23 +02:00
feat(v2): global data + useGlobalData + docs versions dropdown (#2971)
* doc components initial simplification
* doc components initial simplification
* add docContext test
* Add poc of global data system + use it in the theme
* Revert "doc components initial simplification"
This reverts commit f657b4c4
* revert useless changes
* avoid loosing context on docs switch
* fix docs tests
* fix @generated/globalData ts declaration / es import
* typo
* revert bad commit
* refactor navbar in multiple parts + add navbar item types validation + try to fix remaining merge bugs
* add missing watch mode for plugin debug
* fix docs global data integration, move related hooks to docs plugin + convert to TS
* change versions link label
* fix activeClassName react warning
* improve docs global data system + contextual navbar dropdown
* fix bug preventing the deployment
* refactor the global data system to namespace automatically by plugin name + plugin id
* proper NavbarItem comp
* fix tests
* fix snapshot
* extract theme config schema in separate file + rename navbar links to navbar items
* minor typos
* polish docs components/api
* polish useDocs api surface
* fix the docs version suggestions comp + data
* refactors + add docsClientUtils unit tests
* Add documentation
* typo
* Add check for duplicate plugin ids detection
* multi-instance: createData plugin data should be namespaced by plugin instance id
* remove attempt for multi-instance support
This commit is contained in:
parent
a51a56ec42
commit
15e73daae7
53 changed files with 1954 additions and 531 deletions
|
@ -109,6 +109,46 @@ Array [
|
|||
]
|
||||
`;
|
||||
|
||||
exports[`simple website content 3`] = `
|
||||
Object {
|
||||
"pluginName": Object {
|
||||
"pluginId": Object {
|
||||
"latestVersionName": null,
|
||||
"path": "docs",
|
||||
"versions": Array [
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"id": "foo/bar",
|
||||
"path": "/docs/foo/bar",
|
||||
},
|
||||
Object {
|
||||
"id": "foo/baz",
|
||||
"path": "/docs/foo/bazSlug.html",
|
||||
},
|
||||
Object {
|
||||
"id": "hello",
|
||||
"path": "/docs/",
|
||||
},
|
||||
Object {
|
||||
"id": "ipsum",
|
||||
"path": "/docs/ipsum",
|
||||
},
|
||||
Object {
|
||||
"id": "lorem",
|
||||
"path": "/docs/lorem",
|
||||
},
|
||||
],
|
||||
"mainDocId": "hello",
|
||||
"name": null,
|
||||
"path": "/docs",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`site with wrong sidebar file 1`] = `
|
||||
"Bad sidebars file. The document id 'goku' was used in the sidebar, but no document with this id could be found.
|
||||
Available document ids=
|
||||
|
@ -213,6 +253,68 @@ Array [
|
|||
]
|
||||
`;
|
||||
|
||||
exports[`versioned website content 2`] = `
|
||||
Object {
|
||||
"pluginName": Object {
|
||||
"pluginId": Object {
|
||||
"latestVersionName": "1.0.1",
|
||||
"path": "docs",
|
||||
"versions": Array [
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"id": "foo/bar",
|
||||
"path": "/docs/next/foo/barSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "hello",
|
||||
"path": "/docs/next/",
|
||||
},
|
||||
],
|
||||
"mainDocId": "hello",
|
||||
"name": "next",
|
||||
"path": "/docs/next",
|
||||
},
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"id": "foo/bar",
|
||||
"path": "/docs/foo/bar",
|
||||
},
|
||||
Object {
|
||||
"id": "hello",
|
||||
"path": "/docs/",
|
||||
},
|
||||
],
|
||||
"mainDocId": "hello",
|
||||
"name": "1.0.1",
|
||||
"path": "/docs",
|
||||
},
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"id": "foo/bar",
|
||||
"path": "/docs/1.0.0/foo/barSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "foo/baz",
|
||||
"path": "/docs/1.0.0/foo/baz",
|
||||
},
|
||||
Object {
|
||||
"id": "hello",
|
||||
"path": "/docs/1.0.0/",
|
||||
},
|
||||
],
|
||||
"mainDocId": "hello",
|
||||
"name": "1.0.0",
|
||||
"path": "/docs/1.0.0",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`versioned website content: all sidebars 1`] = `
|
||||
Object {
|
||||
"docs": Array [
|
||||
|
|
|
@ -0,0 +1,361 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {
|
||||
ActivePlugin,
|
||||
getActivePlugin,
|
||||
getLatestVersion,
|
||||
getActiveDocContext,
|
||||
getActiveVersion,
|
||||
getDocVersionSuggestions,
|
||||
} from '../../client/docsClientUtils';
|
||||
import {GlobalPluginData, GlobalVersion} from '../../types';
|
||||
import {shuffle} from 'lodash';
|
||||
|
||||
describe('docsClientUtils', () => {
|
||||
test('getActivePlugin', () => {
|
||||
const data: Record<string, GlobalPluginData> = {
|
||||
pluginIosId: {
|
||||
path: 'ios',
|
||||
latestVersionName: 'xyz',
|
||||
versions: [],
|
||||
},
|
||||
pluginAndroidId: {
|
||||
path: 'android',
|
||||
latestVersionName: 'xyz',
|
||||
versions: [],
|
||||
},
|
||||
};
|
||||
|
||||
expect(getActivePlugin(data, '/')).toEqual(undefined);
|
||||
expect(getActivePlugin(data, '/xyz')).toEqual(undefined);
|
||||
|
||||
const activePluginIos: ActivePlugin = {
|
||||
pluginId: 'pluginIosId',
|
||||
pluginData: data.pluginIosId,
|
||||
};
|
||||
expect(getActivePlugin(data, '/ios')).toEqual(activePluginIos);
|
||||
expect(getActivePlugin(data, '/ios/')).toEqual(activePluginIos);
|
||||
expect(getActivePlugin(data, '/ios/abc/def')).toEqual(activePluginIos);
|
||||
|
||||
const activePluginAndroid: ActivePlugin = {
|
||||
pluginId: 'pluginAndroidId',
|
||||
pluginData: data.pluginAndroidId,
|
||||
};
|
||||
expect(getActivePlugin(data, '/android')).toEqual(activePluginAndroid);
|
||||
expect(getActivePlugin(data, '/android/')).toEqual(activePluginAndroid);
|
||||
expect(getActivePlugin(data, '/android/ijk')).toEqual(activePluginAndroid);
|
||||
});
|
||||
|
||||
test('getLatestVersion', () => {
|
||||
const versions: GlobalVersion[] = [
|
||||
{
|
||||
name: 'version1',
|
||||
path: '/???',
|
||||
docs: [],
|
||||
mainDocId: '???',
|
||||
},
|
||||
{
|
||||
name: 'version2',
|
||||
path: '/???',
|
||||
docs: [],
|
||||
mainDocId: '???',
|
||||
},
|
||||
{
|
||||
name: 'version3',
|
||||
path: '/???',
|
||||
docs: [],
|
||||
mainDocId: '???',
|
||||
},
|
||||
];
|
||||
|
||||
expect(
|
||||
getLatestVersion({
|
||||
path: '???',
|
||||
latestVersionName: 'does not exist',
|
||||
versions,
|
||||
}),
|
||||
).toEqual(undefined);
|
||||
expect(
|
||||
getLatestVersion({
|
||||
path: '???',
|
||||
latestVersionName: 'version1',
|
||||
versions,
|
||||
})?.name,
|
||||
).toEqual('version1');
|
||||
expect(
|
||||
getLatestVersion({
|
||||
path: '???',
|
||||
latestVersionName: 'version2',
|
||||
versions,
|
||||
})?.name,
|
||||
).toEqual('version2');
|
||||
expect(
|
||||
getLatestVersion({
|
||||
path: '???',
|
||||
latestVersionName: 'version3',
|
||||
versions,
|
||||
})?.name,
|
||||
).toEqual('version3');
|
||||
});
|
||||
|
||||
test('getActiveVersion', () => {
|
||||
const data: GlobalPluginData = {
|
||||
path: 'docs',
|
||||
latestVersionName: 'version2',
|
||||
versions: [
|
||||
{
|
||||
name: 'next',
|
||||
path: '/docs/next',
|
||||
docs: [],
|
||||
mainDocId: '???',
|
||||
},
|
||||
{
|
||||
name: 'version2',
|
||||
path: '/docs',
|
||||
docs: [],
|
||||
mainDocId: '???',
|
||||
},
|
||||
{
|
||||
name: 'version1',
|
||||
path: '/docs/version1',
|
||||
docs: [],
|
||||
mainDocId: '???',
|
||||
},
|
||||
],
|
||||
};
|
||||
expect(getActiveVersion(data, '/docs/next')?.name).toEqual('next');
|
||||
expect(getActiveVersion(data, '/docs/next/')?.name).toEqual('next');
|
||||
expect(getActiveVersion(data, '/docs/next/someDoc')?.name).toEqual('next');
|
||||
|
||||
expect(getActiveVersion(data, '/docs')?.name).toEqual('version2');
|
||||
expect(getActiveVersion(data, '/docs/')?.name).toEqual('version2');
|
||||
expect(getActiveVersion(data, '/docs/someDoc')?.name).toEqual('version2');
|
||||
|
||||
expect(getActiveVersion(data, '/docs/version1')?.name).toEqual('version1');
|
||||
expect(getActiveVersion(data, '/docs/version1')?.name).toEqual('version1');
|
||||
expect(getActiveVersion(data, '/docs/version1/someDoc')?.name).toEqual(
|
||||
'version1',
|
||||
);
|
||||
});
|
||||
|
||||
test('getActiveDocContext', () => {
|
||||
const versionNext: GlobalVersion = {
|
||||
name: 'next',
|
||||
path: '/docs/next',
|
||||
mainDocId: 'doc1',
|
||||
docs: [
|
||||
{
|
||||
id: 'doc1',
|
||||
path: '/docs/next/',
|
||||
},
|
||||
{
|
||||
id: 'doc2',
|
||||
path: '/docs/next/doc2',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const version2: GlobalVersion = {
|
||||
name: 'version2',
|
||||
path: '/docs',
|
||||
mainDocId: 'doc1',
|
||||
docs: [
|
||||
{
|
||||
id: 'doc1',
|
||||
path: '/docs/',
|
||||
},
|
||||
{
|
||||
id: 'doc2',
|
||||
path: '/docs/doc2',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const version1: GlobalVersion = {
|
||||
name: 'version1',
|
||||
path: '/docs/version1',
|
||||
mainDocId: 'doc1',
|
||||
docs: [
|
||||
{
|
||||
id: 'doc1',
|
||||
path: '/docs/version1/',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// shuffle, because order shouldn't matter
|
||||
const versions: GlobalVersion[] = shuffle([
|
||||
versionNext,
|
||||
version2,
|
||||
version1,
|
||||
]);
|
||||
|
||||
const data: GlobalPluginData = {
|
||||
path: 'docs',
|
||||
latestVersionName: 'version2',
|
||||
versions,
|
||||
};
|
||||
|
||||
expect(getActiveDocContext(data, '/doesNotExist')).toEqual({
|
||||
activeVersion: undefined,
|
||||
activeDoc: undefined,
|
||||
alternateDocVersions: {},
|
||||
});
|
||||
|
||||
expect(getActiveDocContext(data, '/docs/next/doesNotExist')).toEqual({
|
||||
activeVersion: versionNext,
|
||||
activeDoc: undefined,
|
||||
alternateDocVersions: {},
|
||||
});
|
||||
|
||||
expect(getActiveDocContext(data, '/docs/next')).toEqual({
|
||||
activeVersion: versionNext,
|
||||
activeDoc: versionNext.docs[0],
|
||||
alternateDocVersions: {
|
||||
next: versionNext.docs[0],
|
||||
version2: version2.docs[0],
|
||||
version1: version1.docs[0],
|
||||
},
|
||||
});
|
||||
expect(getActiveDocContext(data, '/docs/next/doc2')).toEqual({
|
||||
activeVersion: versionNext,
|
||||
activeDoc: versionNext.docs[1],
|
||||
alternateDocVersions: {
|
||||
next: versionNext.docs[1],
|
||||
version2: version2.docs[1],
|
||||
version1: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
expect(getActiveDocContext(data, '/docs/')).toEqual({
|
||||
activeVersion: version2,
|
||||
activeDoc: version2.docs[0],
|
||||
alternateDocVersions: {
|
||||
next: versionNext.docs[0],
|
||||
version2: version2.docs[0],
|
||||
version1: version1.docs[0],
|
||||
},
|
||||
});
|
||||
expect(getActiveDocContext(data, '/docs/doc2')).toEqual({
|
||||
activeVersion: version2,
|
||||
activeDoc: version2.docs[1],
|
||||
alternateDocVersions: {
|
||||
next: versionNext.docs[1],
|
||||
version2: version2.docs[1],
|
||||
version1: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
expect(getActiveDocContext(data, '/docs/version1')).toEqual({
|
||||
activeVersion: version1,
|
||||
activeDoc: version1.docs[0],
|
||||
alternateDocVersions: {
|
||||
next: versionNext.docs[0],
|
||||
version2: version2.docs[0],
|
||||
version1: version1.docs[0],
|
||||
},
|
||||
});
|
||||
expect(getActiveDocContext(data, '/docs/version1/doc2')).toEqual({
|
||||
activeVersion: version1,
|
||||
activeDoc: undefined,
|
||||
alternateDocVersions: {},
|
||||
});
|
||||
});
|
||||
|
||||
test('getDocVersionSuggestions', () => {
|
||||
const versionNext: GlobalVersion = {
|
||||
name: 'next',
|
||||
path: '/docs/next',
|
||||
mainDocId: 'doc1',
|
||||
docs: [
|
||||
{
|
||||
id: 'doc1',
|
||||
path: '/docs/next/',
|
||||
},
|
||||
{
|
||||
id: 'doc2',
|
||||
path: '/docs/next/doc2',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const version2: GlobalVersion = {
|
||||
name: 'version2',
|
||||
path: '/docs',
|
||||
mainDocId: 'doc1',
|
||||
docs: [
|
||||
{
|
||||
id: 'doc1',
|
||||
path: '/docs/',
|
||||
},
|
||||
{
|
||||
id: 'doc2',
|
||||
path: '/docs/doc2',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const version1: GlobalVersion = {
|
||||
name: 'version1',
|
||||
path: '/docs/version1',
|
||||
mainDocId: 'doc1',
|
||||
docs: [
|
||||
{
|
||||
id: 'doc1',
|
||||
path: '/docs/version1/',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// shuffle, because order shouldn't matter
|
||||
const versions: GlobalVersion[] = shuffle([
|
||||
versionNext,
|
||||
version2,
|
||||
version1,
|
||||
]);
|
||||
|
||||
const data: GlobalPluginData = {
|
||||
path: 'docs',
|
||||
latestVersionName: 'version2',
|
||||
versions,
|
||||
};
|
||||
|
||||
expect(getDocVersionSuggestions(data, '/doesNotExist')).toEqual({
|
||||
latestDocSuggestion: undefined,
|
||||
latestVersionSuggestion: version2,
|
||||
});
|
||||
|
||||
expect(getDocVersionSuggestions(data, '/docs/next')).toEqual({
|
||||
latestDocSuggestion: version2.docs[0],
|
||||
latestVersionSuggestion: version2,
|
||||
});
|
||||
expect(getDocVersionSuggestions(data, '/docs/next/doc2')).toEqual({
|
||||
latestDocSuggestion: version2.docs[1],
|
||||
latestVersionSuggestion: version2,
|
||||
});
|
||||
|
||||
// nothing to suggest, we are already on latest version
|
||||
expect(getDocVersionSuggestions(data, '/docs/')).toEqual({
|
||||
latestDocSuggestion: undefined,
|
||||
latestVersionSuggestion: undefined,
|
||||
});
|
||||
expect(getDocVersionSuggestions(data, '/docs/doc2')).toEqual({
|
||||
latestDocSuggestion: undefined,
|
||||
latestVersionSuggestion: undefined,
|
||||
});
|
||||
|
||||
expect(getDocVersionSuggestions(data, '/docs/version1/')).toEqual({
|
||||
latestDocSuggestion: version2.docs[0],
|
||||
latestVersionSuggestion: version2,
|
||||
});
|
||||
expect(getDocVersionSuggestions(data, '/docs/version1/doc2')).toEqual({
|
||||
latestDocSuggestion: undefined, // because /docs/version1/doc2 does not exist
|
||||
latestVersionSuggestion: version2,
|
||||
});
|
||||
});
|
||||
});
|
|
@ -25,6 +25,7 @@ const createFakeActions = (
|
|||
routeConfigs: RouteConfig[],
|
||||
contentDir,
|
||||
dataContainer?,
|
||||
globalDataContainer?,
|
||||
) => {
|
||||
return {
|
||||
addRoute: (config: RouteConfig) => {
|
||||
|
@ -36,6 +37,9 @@ const createFakeActions = (
|
|||
}
|
||||
return path.join(contentDir, name);
|
||||
},
|
||||
setGlobalData: (data) => {
|
||||
globalDataContainer.pluginName = {pluginId: data};
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -166,6 +170,7 @@ describe('simple website', () => {
|
|||
expect(versionToSidebars).toEqual({});
|
||||
expect(docsMetadata.hello).toEqual({
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: true,
|
||||
permalink: '/docs/',
|
||||
previous: {
|
||||
|
@ -176,11 +181,11 @@ describe('simple website', () => {
|
|||
source: path.join('@site', pluginPath, 'hello.md'),
|
||||
title: 'Hello, World !',
|
||||
description: 'Hi, Endilie here :)',
|
||||
latestVersionMainDocPermalink: undefined,
|
||||
});
|
||||
|
||||
expect(docsMetadata['foo/bar']).toEqual({
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
next: {
|
||||
title: 'baz',
|
||||
|
@ -191,17 +196,18 @@ describe('simple website', () => {
|
|||
source: path.join('@site', pluginPath, 'foo', 'bar.md'),
|
||||
title: 'Bar',
|
||||
description: 'This is custom description',
|
||||
latestVersionMainDocPermalink: undefined,
|
||||
});
|
||||
|
||||
expect(docsSidebars).toMatchSnapshot();
|
||||
|
||||
const routeConfigs = [];
|
||||
const dataContainer = {};
|
||||
const globalDataContainer = {};
|
||||
const actions = createFakeActions(
|
||||
routeConfigs,
|
||||
pluginContentDir,
|
||||
dataContainer,
|
||||
globalDataContainer,
|
||||
);
|
||||
|
||||
await plugin.contentLoaded({
|
||||
|
@ -219,6 +225,7 @@ describe('simple website', () => {
|
|||
|
||||
expect(routeConfigs).not.toEqual([]);
|
||||
expect(routeConfigs).toMatchSnapshot();
|
||||
expect(globalDataContainer).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -313,6 +320,7 @@ describe('versioned website', () => {
|
|||
expect(docsMetadata['version-1.0.1/foo/baz']).toBeUndefined();
|
||||
expect(docsMetadata['foo/bar']).toEqual({
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/next/foo/barSlug',
|
||||
source: path.join('@site', routeBasePath, 'foo', 'bar.md'),
|
||||
|
@ -327,6 +335,7 @@ describe('versioned website', () => {
|
|||
});
|
||||
expect(docsMetadata.hello).toEqual({
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: true,
|
||||
permalink: '/docs/next/',
|
||||
source: path.join('@site', routeBasePath, 'hello.md'),
|
||||
|
@ -341,6 +350,7 @@ describe('versioned website', () => {
|
|||
});
|
||||
expect(docsMetadata['version-1.0.1/hello']).toEqual({
|
||||
id: 'version-1.0.1/hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: true,
|
||||
permalink: '/docs/',
|
||||
source: path.join(
|
||||
|
@ -357,10 +367,10 @@ describe('versioned website', () => {
|
|||
title: 'bar',
|
||||
permalink: '/docs/foo/bar',
|
||||
},
|
||||
latestVersionMainDocPermalink: undefined,
|
||||
});
|
||||
expect(docsMetadata['version-1.0.0/foo/baz']).toEqual({
|
||||
id: 'version-1.0.0/foo/baz',
|
||||
unversionedId: 'foo/baz',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/1.0.0/foo/baz',
|
||||
source: path.join(
|
||||
|
@ -391,10 +401,12 @@ describe('versioned website', () => {
|
|||
);
|
||||
const routeConfigs = [];
|
||||
const dataContainer = {};
|
||||
const globalDataContainer = {};
|
||||
const actions = createFakeActions(
|
||||
routeConfigs,
|
||||
pluginContentDir,
|
||||
dataContainer,
|
||||
globalDataContainer,
|
||||
);
|
||||
await plugin.contentLoaded({
|
||||
content,
|
||||
|
@ -438,5 +450,6 @@ describe('versioned website', () => {
|
|||
|
||||
expect(routeConfigs).not.toEqual([]);
|
||||
expect(routeConfigs).toMatchSnapshot();
|
||||
expect(globalDataContainer).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -46,21 +46,21 @@ describe('simple site', () => {
|
|||
|
||||
expect(dataA).toEqual({
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/foo/bar',
|
||||
source: path.join('@site', routeBasePath, sourceA),
|
||||
title: 'Bar',
|
||||
description: 'This is custom description',
|
||||
latestVersionMainDocPermalink: undefined,
|
||||
});
|
||||
expect(dataB).toEqual({
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/hello',
|
||||
source: path.join('@site', routeBasePath, sourceB),
|
||||
title: 'Hello, World !',
|
||||
description: `Hi, Endilie here :)`,
|
||||
latestVersionMainDocPermalink: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -81,6 +81,7 @@ describe('simple site', () => {
|
|||
|
||||
expect(data).toEqual({
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: true,
|
||||
permalink: '/docs/',
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
|
@ -106,6 +107,7 @@ describe('simple site', () => {
|
|||
|
||||
expect(data).toEqual({
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: true,
|
||||
permalink: '/docs/',
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
|
@ -133,6 +135,7 @@ describe('simple site', () => {
|
|||
|
||||
expect(data).toEqual({
|
||||
id: 'foo/baz',
|
||||
unversionedId: 'foo/baz',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/foo/bazSlug.html',
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
|
@ -140,7 +143,6 @@ describe('simple site', () => {
|
|||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website/docs/foo/baz.md',
|
||||
description: 'Images',
|
||||
latestVersionMainDocPermalink: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -160,13 +162,13 @@ describe('simple site', () => {
|
|||
|
||||
expect(data).toEqual({
|
||||
id: 'lorem',
|
||||
unversionedId: 'lorem',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/lorem',
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
title: 'lorem',
|
||||
editUrl: 'https://github.com/customUrl/docs/lorem.md',
|
||||
description: 'Lorem ipsum.',
|
||||
latestVersionMainDocPermalink: undefined,
|
||||
});
|
||||
|
||||
// unrelated frontmatter is not part of metadata
|
||||
|
@ -192,6 +194,7 @@ describe('simple site', () => {
|
|||
|
||||
expect(data).toEqual({
|
||||
id: 'lorem',
|
||||
unversionedId: 'lorem',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/lorem',
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
|
@ -200,7 +203,6 @@ describe('simple site', () => {
|
|||
description: 'Lorem ipsum.',
|
||||
lastUpdatedAt: 1539502055,
|
||||
lastUpdatedBy: 'Author',
|
||||
latestVersionMainDocPermalink: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -222,6 +224,7 @@ describe('simple site', () => {
|
|||
|
||||
expect(data).toEqual({
|
||||
id: 'ipsum',
|
||||
unversionedId: 'ipsum',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/ipsum',
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
|
@ -230,7 +233,6 @@ describe('simple site', () => {
|
|||
description: 'Lorem ipsum.',
|
||||
lastUpdatedAt: 1539502055,
|
||||
lastUpdatedBy: 'Author',
|
||||
latestVersionMainDocPermalink: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -327,6 +329,7 @@ describe('versioned site', () => {
|
|||
|
||||
expect(dataA).toEqual({
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/next/foo/barSlug',
|
||||
source: path.join('@site', routeBasePath, sourceA),
|
||||
|
@ -336,6 +339,7 @@ describe('versioned site', () => {
|
|||
});
|
||||
expect(dataB).toEqual({
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/next/hello',
|
||||
source: path.join('@site', routeBasePath, sourceB),
|
||||
|
@ -387,6 +391,7 @@ describe('versioned site', () => {
|
|||
|
||||
expect(dataA).toEqual({
|
||||
id: 'version-1.0.0/foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/1.0.0/foo/barSlug',
|
||||
source: path.join('@site', path.relative(siteDir, versionedDir), sourceA),
|
||||
|
@ -396,6 +401,7 @@ describe('versioned site', () => {
|
|||
});
|
||||
expect(dataB).toEqual({
|
||||
id: 'version-1.0.0/hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/1.0.0/hello',
|
||||
source: path.join('@site', path.relative(siteDir, versionedDir), sourceB),
|
||||
|
@ -405,6 +411,7 @@ describe('versioned site', () => {
|
|||
});
|
||||
expect(dataC).toEqual({
|
||||
id: 'version-1.0.1/foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/foo/bar',
|
||||
source: path.join('@site', path.relative(siteDir, versionedDir), sourceC),
|
||||
|
@ -414,6 +421,7 @@ describe('versioned site', () => {
|
|||
});
|
||||
expect(dataD).toEqual({
|
||||
id: 'version-1.0.1/hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/hello',
|
||||
source: path.join('@site', path.relative(siteDir, versionedDir), sourceD),
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {matchPath} from '@docusaurus/router';
|
||||
|
||||
import {GlobalPluginData, GlobalVersion, GlobalDoc} from '../types';
|
||||
|
||||
// This code is not part of the api surface, not in ./theme on purpose
|
||||
|
||||
// Short/convenient type aliases
|
||||
type Version = GlobalVersion;
|
||||
type Doc = GlobalDoc;
|
||||
|
||||
export type ActivePlugin = {
|
||||
pluginId: string;
|
||||
pluginData: GlobalPluginData;
|
||||
};
|
||||
|
||||
// get the data of the plugin that is currently "active"
|
||||
// ie the docs of that plugin are currently browsed
|
||||
// it is useful to support multiple docs plugin instances
|
||||
export const getActivePlugin = (
|
||||
allPluginDatas: Record<string, GlobalPluginData>,
|
||||
pathname: string,
|
||||
): ActivePlugin | undefined => {
|
||||
const activeEntry = Object.entries(allPluginDatas).find(
|
||||
([_id, pluginData]) => {
|
||||
return !!matchPath(pathname, {
|
||||
path: `/${pluginData.path}`,
|
||||
exact: false,
|
||||
strict: false,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
return activeEntry
|
||||
? {pluginId: activeEntry[0], pluginData: activeEntry[1]}
|
||||
: undefined;
|
||||
};
|
||||
|
||||
export type ActiveDocContext = {
|
||||
activeVersion?: Version;
|
||||
activeDoc?: Doc;
|
||||
alternateDocVersions: Record<string, Doc>;
|
||||
};
|
||||
|
||||
export const getLatestVersion = (data: GlobalPluginData): Version => {
|
||||
return data.versions.find(
|
||||
(version) => version.name === data.latestVersionName,
|
||||
)!;
|
||||
};
|
||||
|
||||
// Note: return undefined on doc-unrelated pages,
|
||||
// because there's no version currently considered as active
|
||||
export const getActiveVersion = (
|
||||
data: GlobalPluginData,
|
||||
pathname: string,
|
||||
): Version | undefined => {
|
||||
const lastVersion = getLatestVersion(data);
|
||||
// Last version is a route like /docs/*,
|
||||
// we need to try to match it last or it would match /docs/version-1.0/* as well
|
||||
const orderedVersionsMetadata = [
|
||||
...data.versions.filter((version) => version !== lastVersion),
|
||||
lastVersion,
|
||||
];
|
||||
return orderedVersionsMetadata.find((version) => {
|
||||
return !!matchPath(pathname, {
|
||||
path: version.path,
|
||||
exact: false,
|
||||
strict: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const getActiveDocContext = (
|
||||
data: GlobalPluginData,
|
||||
pathname: string,
|
||||
): ActiveDocContext => {
|
||||
const activeVersion = getActiveVersion(data, pathname);
|
||||
const activeDoc = activeVersion?.docs.find(
|
||||
(doc) =>
|
||||
!!matchPath(pathname, {
|
||||
path: doc.path,
|
||||
exact: true,
|
||||
strict: false,
|
||||
}),
|
||||
);
|
||||
|
||||
function getAlternateVersionDocs(
|
||||
docId: string,
|
||||
): ActiveDocContext['alternateDocVersions'] {
|
||||
const result: ActiveDocContext['alternateDocVersions'] = {};
|
||||
data.versions.forEach((version) => {
|
||||
version.docs.forEach((doc) => {
|
||||
if (doc.id === docId) {
|
||||
result[version.name!] = doc;
|
||||
}
|
||||
});
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
const alternateVersionDocs = activeDoc
|
||||
? getAlternateVersionDocs(activeDoc.id)
|
||||
: {};
|
||||
|
||||
return {
|
||||
activeVersion,
|
||||
activeDoc,
|
||||
alternateDocVersions: alternateVersionDocs,
|
||||
};
|
||||
};
|
||||
|
||||
export type DocVersionSuggestions = {
|
||||
// suggest the same doc, in latest version (if exist)
|
||||
latestDocSuggestion?: GlobalDoc;
|
||||
// suggest the latest version
|
||||
latestVersionSuggestion?: GlobalVersion;
|
||||
};
|
||||
|
||||
export const getDocVersionSuggestions = (
|
||||
data: GlobalPluginData,
|
||||
pathname: string,
|
||||
): DocVersionSuggestions => {
|
||||
const latestVersion = getLatestVersion(data);
|
||||
const activeDocContext = getActiveDocContext(data, pathname);
|
||||
|
||||
// We only suggest another doc/version if user is not using the latest version
|
||||
const isNotOnLatestVersion = activeDocContext.activeVersion !== latestVersion;
|
||||
|
||||
const latestDocSuggestion: GlobalDoc | undefined = isNotOnLatestVersion
|
||||
? activeDocContext?.alternateDocVersions[latestVersion.name!]
|
||||
: undefined;
|
||||
|
||||
const latestVersionSuggestion = isNotOnLatestVersion
|
||||
? latestVersion
|
||||
: undefined;
|
||||
|
||||
return {latestDocSuggestion, latestVersionSuggestion};
|
||||
};
|
|
@ -8,6 +8,7 @@
|
|||
import groupBy from 'lodash.groupby';
|
||||
import pick from 'lodash.pick';
|
||||
import pickBy from 'lodash.pickby';
|
||||
import sortBy from 'lodash.sortby';
|
||||
import globby from 'globby';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
|
@ -49,6 +50,10 @@ import {
|
|||
VersionToSidebars,
|
||||
SidebarItem,
|
||||
DocsSidebarItem,
|
||||
GlobalPluginData,
|
||||
DocsVersion,
|
||||
GlobalVersion,
|
||||
GlobalDoc,
|
||||
} from './types';
|
||||
import {Configuration} from 'webpack';
|
||||
import {docsVersion} from './version';
|
||||
|
@ -56,22 +61,6 @@ import {VERSIONS_JSON_FILE} from './constants';
|
|||
import {PluginOptionSchema} from './pluginOptionSchema';
|
||||
import {ValidationError} from '@hapi/joi';
|
||||
|
||||
function getFirstDocLinkOfSidebar(
|
||||
sidebarItems: DocsSidebarItem[],
|
||||
): string | null {
|
||||
for (const sidebarItem of sidebarItems) {
|
||||
if (sidebarItem.type === 'category') {
|
||||
const url = getFirstDocLinkOfSidebar(sidebarItem.items);
|
||||
if (url) {
|
||||
return url;
|
||||
}
|
||||
} else {
|
||||
return sidebarItem.href;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export default function pluginContentDocs(
|
||||
context: LoadContext,
|
||||
options: PluginOptions,
|
||||
|
@ -92,6 +81,7 @@ export default function pluginContentDocs(
|
|||
const dataDir = path.join(
|
||||
generatedFilesDir,
|
||||
'docusaurus-plugin-content-docs',
|
||||
// options.id ?? 'default', // TODO support multi-instance
|
||||
);
|
||||
|
||||
// Versioning.
|
||||
|
@ -329,11 +319,23 @@ Available document ids=
|
|||
}
|
||||
|
||||
const {docLayoutComponent, docItemComponent, routeBasePath} = options;
|
||||
const {addRoute, createData} = actions;
|
||||
const {addRoute, createData, setGlobalData} = actions;
|
||||
|
||||
const pluginInstanceGlobalData: GlobalPluginData = {
|
||||
path: options.path,
|
||||
latestVersionName: versioning.latestVersion,
|
||||
// Initialized empty, will be mutated
|
||||
versions: [],
|
||||
};
|
||||
|
||||
setGlobalData<GlobalPluginData>(pluginInstanceGlobalData);
|
||||
|
||||
const aliasedSource = (source: string) =>
|
||||
`~docs/${path.relative(dataDir, source)}`;
|
||||
|
||||
const createDocsBaseMetadata = (version?: string): DocsBaseMetadata => {
|
||||
const createDocsBaseMetadata = (
|
||||
version: DocsVersion,
|
||||
): DocsBaseMetadata => {
|
||||
const {docsSidebars, permalinkToSidebar, versionToSidebars} = content;
|
||||
const neededSidebars: Set<string> =
|
||||
versionToSidebars[version!] || new Set();
|
||||
|
@ -377,13 +379,19 @@ Available document ids=
|
|||
return routes.sort((a, b) => a.path.localeCompare(b.path));
|
||||
};
|
||||
|
||||
// We want latest version route to have lower priority
|
||||
// Otherwise `/docs/next/foo` would match
|
||||
// `/docs/:route` instead of `/docs/next/:route`.
|
||||
const getVersionRoutePriority = (version: DocsVersion) =>
|
||||
version === versioning.latestVersion ? -1 : undefined;
|
||||
|
||||
// This is the base route of the document root (for a doc given version)
|
||||
// (/docs, /docs/next, /docs/1.0 etc...)
|
||||
// The component applies the layout and renders the appropriate doc
|
||||
const addBaseRoute = async (
|
||||
const addVersionRoute = async (
|
||||
docsBasePath: string,
|
||||
docsBaseMetadata: DocsBaseMetadata,
|
||||
routes: RouteConfig[],
|
||||
docs: Metadata[],
|
||||
priority?: number,
|
||||
) => {
|
||||
const docsBaseMetadataPath = await createData(
|
||||
|
@ -391,18 +399,38 @@ Available document ids=
|
|||
JSON.stringify(docsBaseMetadata, null, 2),
|
||||
);
|
||||
|
||||
const docsRoutes = await genRoutes(docs);
|
||||
|
||||
const mainDoc: Metadata =
|
||||
docs.find((doc) => doc.unversionedId === options.homePageId) ??
|
||||
docs[0];
|
||||
|
||||
const toGlobalDataDoc = (doc: Metadata): GlobalDoc => ({
|
||||
id: doc.unversionedId,
|
||||
path: doc.permalink,
|
||||
});
|
||||
|
||||
pluginInstanceGlobalData.versions.push({
|
||||
name: docsBaseMetadata.version,
|
||||
path: docsBasePath,
|
||||
mainDocId: mainDoc.unversionedId,
|
||||
docs: docs
|
||||
.map(toGlobalDataDoc)
|
||||
// stable ordering, useful for tests
|
||||
.sort((a, b) => a.id.localeCompare(b.id)),
|
||||
});
|
||||
|
||||
addRoute({
|
||||
path: docsBasePath,
|
||||
exact: false, // allow matching /docs/* as well
|
||||
component: docLayoutComponent, // main docs component (DocPage)
|
||||
routes, // subroute for each doc
|
||||
routes: docsRoutes, // subroute for each doc
|
||||
modules: {
|
||||
docsMetadata: aliasedSource(docsBaseMetadataPath),
|
||||
},
|
||||
priority,
|
||||
});
|
||||
};
|
||||
|
||||
// If versioning is enabled, we cleverly chunk the generated routes
|
||||
// to be by version and pick only needed base metadata.
|
||||
if (versioning.enabled) {
|
||||
|
@ -410,27 +438,10 @@ Available document ids=
|
|||
Object.values(content.docsMetadata),
|
||||
'version',
|
||||
);
|
||||
const rootUrl =
|
||||
options.homePageId && content.docsMetadata[options.homePageId]
|
||||
? normalizeUrl([baseUrl, routeBasePath])
|
||||
: getFirstDocLinkOfSidebar(
|
||||
content.docsSidebars[
|
||||
`version-${versioning.latestVersion}/docs`
|
||||
],
|
||||
);
|
||||
if (!rootUrl) {
|
||||
throw new Error('Bad sidebars file. No document linked');
|
||||
}
|
||||
Object.values(content.docsMetadata).forEach((docMetadata) => {
|
||||
if (docMetadata.version !== versioning.latestVersion) {
|
||||
docMetadata.latestVersionMainDocPermalink = rootUrl;
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
Object.keys(docsMetadataByVersion).map(async (version) => {
|
||||
const routes: RouteConfig[] = await genRoutes(
|
||||
docsMetadataByVersion[version],
|
||||
);
|
||||
const docsMetadata = docsMetadataByVersion[version];
|
||||
|
||||
const isLatestVersion = version === versioning.latestVersion;
|
||||
const docsBaseRoute = normalizeUrl([
|
||||
|
@ -440,23 +451,29 @@ Available document ids=
|
|||
]);
|
||||
const docsBaseMetadata = createDocsBaseMetadata(version);
|
||||
|
||||
return addBaseRoute(
|
||||
await addVersionRoute(
|
||||
docsBaseRoute,
|
||||
docsBaseMetadata,
|
||||
routes,
|
||||
// We want latest version route config to be placed last in the
|
||||
// generated routeconfig. Otherwise, `/docs/next/foo` will match
|
||||
// `/docs/:route` instead of `/docs/next/:route`.
|
||||
isLatestVersion ? -1 : undefined,
|
||||
docsMetadata,
|
||||
getVersionRoutePriority(version),
|
||||
);
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
const routes = await genRoutes(Object.values(content.docsMetadata));
|
||||
const docsBaseMetadata = createDocsBaseMetadata();
|
||||
const docsMetadata = Object.values(content.docsMetadata);
|
||||
const docsBaseMetadata = createDocsBaseMetadata(null);
|
||||
const docsBaseRoute = normalizeUrl([baseUrl, routeBasePath]);
|
||||
await addBaseRoute(docsBaseRoute, docsBaseMetadata, routes);
|
||||
await addVersionRoute(docsBaseRoute, docsBaseMetadata, docsMetadata);
|
||||
}
|
||||
|
||||
// ensure version ordering on the global data (latest first)
|
||||
pluginInstanceGlobalData.versions = sortBy(
|
||||
pluginInstanceGlobalData.versions,
|
||||
(versionMetadata: GlobalVersion) => {
|
||||
const orderedVersionNames = ['next', ...versions];
|
||||
return orderedVersionNames.indexOf(versionMetadata.name!);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
async routesLoaded(routes) {
|
||||
|
|
|
@ -123,9 +123,9 @@ export default async function processMetadata({
|
|||
throw new Error('Document id cannot include "/".');
|
||||
}
|
||||
const id = dirName !== '.' ? `${dirName}/${baseID}` : baseID;
|
||||
const idWithoutVersion = version ? removeVersionPrefix(id, version) : id;
|
||||
const unversionedId = version ? removeVersionPrefix(id, version) : id;
|
||||
|
||||
const isDocsHomePage = idWithoutVersion === homePageId;
|
||||
const isDocsHomePage = unversionedId === homePageId;
|
||||
if (frontMatter.slug && isDocsHomePage) {
|
||||
throw new Error(
|
||||
`The docs homepage (homePageId=${homePageId}) is not allowed to have a frontmatter slug=${frontMatter.slug} => you have to chooser either homePageId or slug, not both`,
|
||||
|
@ -169,6 +169,7 @@ export default async function processMetadata({
|
|||
// Adding properties to object after instantiation will cause hidden
|
||||
// class transitions.
|
||||
const metadata: MetadataRaw = {
|
||||
unversionedId,
|
||||
id,
|
||||
isDocsHomePage,
|
||||
title,
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {useLocation} from '@docusaurus/router';
|
||||
import {
|
||||
useAllPluginInstancesData,
|
||||
usePluginData,
|
||||
} from '@docusaurus/useGlobalData';
|
||||
|
||||
import {GlobalPluginData, GlobalVersion} from '../../types';
|
||||
import {
|
||||
getActivePlugin,
|
||||
getLatestVersion,
|
||||
getActiveVersion,
|
||||
getActiveDocContext,
|
||||
getDocVersionSuggestions,
|
||||
} from '../../client/docsClientUtils';
|
||||
|
||||
const useAllDocsData = (): Record<string, GlobalPluginData> =>
|
||||
useAllPluginInstancesData('docusaurus-plugin-content-docs');
|
||||
|
||||
const useDocsData = (pluginId: string | undefined) =>
|
||||
usePluginData('docusaurus-plugin-content-docs', pluginId) as GlobalPluginData;
|
||||
|
||||
export const useActivePlugin = () => {
|
||||
const data = useAllDocsData();
|
||||
const {pathname} = useLocation();
|
||||
return getActivePlugin(data, pathname);
|
||||
};
|
||||
|
||||
// versions are returned ordered (most recent first)
|
||||
export const useVersions = (pluginId: string | undefined): GlobalVersion[] => {
|
||||
const data = useDocsData(pluginId);
|
||||
return data.versions;
|
||||
};
|
||||
|
||||
export const useLatestVersion = (pluginId: string | undefined) => {
|
||||
const data = useDocsData(pluginId);
|
||||
return getLatestVersion(data);
|
||||
};
|
||||
|
||||
// Note: return undefined on doc-unrelated pages,
|
||||
// because there's no version currently considered as active
|
||||
export const useActiveVersion = (pluginId: string | undefined) => {
|
||||
const data = useDocsData(pluginId);
|
||||
const {pathname} = useLocation();
|
||||
return getActiveVersion(data, pathname);
|
||||
};
|
||||
|
||||
export const useActiveDocContext = (pluginId: string | undefined) => {
|
||||
const data = useDocsData(pluginId);
|
||||
const {pathname} = useLocation();
|
||||
return getActiveDocContext(data, pathname);
|
||||
};
|
||||
|
||||
// Useful to say "hey, you are not on the latest docs version, please switch"
|
||||
export const useDocVersionSuggestions = (pluginId: string | undefined) => {
|
||||
const data = useDocsData(pluginId);
|
||||
const {pathname} = useLocation();
|
||||
return getDocVersionSuggestions(data, pathname);
|
||||
};
|
|
@ -5,6 +5,11 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line spaced-comment
|
||||
/// <reference types="@docusaurus/module-type-aliases" />
|
||||
|
||||
export type DocsVersion = string | null; // null = unversioned sites
|
||||
|
||||
export interface MetadataOptions {
|
||||
routeBasePath: string;
|
||||
homePageId?: string;
|
||||
|
@ -19,6 +24,7 @@ export interface PathOptions {
|
|||
}
|
||||
|
||||
export interface PluginOptions extends MetadataOptions, PathOptions {
|
||||
id?: string;
|
||||
include: string[];
|
||||
docLayoutComponent: string;
|
||||
docItemComponent: string;
|
||||
|
@ -112,6 +118,7 @@ export interface LastUpdateData {
|
|||
}
|
||||
|
||||
export interface MetadataRaw extends LastUpdateData {
|
||||
unversionedId: string;
|
||||
id: string;
|
||||
isDocsHomePage: boolean;
|
||||
title: string;
|
||||
|
@ -121,7 +128,6 @@ export interface MetadataRaw extends LastUpdateData {
|
|||
sidebar_label?: string;
|
||||
editUrl?: string;
|
||||
version?: string;
|
||||
latestVersionMainDocPermalink?: string;
|
||||
}
|
||||
|
||||
export interface Paginator {
|
||||
|
@ -167,7 +173,7 @@ export type DocsBaseMetadata = Pick<
|
|||
LoadedContent,
|
||||
'docsSidebars' | 'permalinkToSidebar'
|
||||
> & {
|
||||
version?: string;
|
||||
version: string | null;
|
||||
};
|
||||
|
||||
export type VersioningEnv = {
|
||||
|
@ -182,3 +188,21 @@ export interface Env {
|
|||
versioning: VersioningEnv;
|
||||
// TODO: translation
|
||||
}
|
||||
|
||||
export type GlobalDoc = {
|
||||
id: string;
|
||||
path: string;
|
||||
};
|
||||
|
||||
export type GlobalVersion = {
|
||||
name: DocsVersion;
|
||||
path: string;
|
||||
mainDocId: string; // home doc (if docs homepage configured), or first doc
|
||||
docs: GlobalDoc[];
|
||||
};
|
||||
|
||||
export type GlobalPluginData = {
|
||||
path: string;
|
||||
latestVersionName: DocsVersion;
|
||||
versions: GlobalVersion[];
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue