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:
Sébastien Lorber 2020-07-21 11:16:08 +02:00 committed by GitHub
parent a51a56ec42
commit 15e73daae7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 1954 additions and 531 deletions

View file

@ -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};
};