mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-15 01:57:28 +02:00
chore: backport retro compatible commits for the Docusaurus v2.1 release (#8033)
Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com> Co-authored-by: Joshua Chen <sidachen2003@gmail.com> Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com> Co-authored-by: whiteand <andrewbeletskiy@gmail.com> Co-authored-by: yzhe819 <68207314+yzhe819@users.noreply.github.com> Co-authored-by: Ngô Quốc Đạt <56961917+datlechin@users.noreply.github.com> Co-authored-by: Kevin Østerkilde <kevin@oesterkilde.dk> Co-authored-by: Bagdasar Ovsepyan <66012777+b-ovsepian@users.noreply.github.com> Co-authored-by: Yoni Chechik <chechik.yoni@gmail.com> Co-authored-by: adventure-yunfei <adventure.yunfei@gmail.com> Co-authored-by: Morgane Dubus <30866152+mdubus@users.noreply.github.com>
This commit is contained in:
parent
bb65b5c578
commit
26d2b9a018
73 changed files with 764 additions and 250 deletions
|
@ -25,10 +25,12 @@ module.exports = {
|
||||||
// But you can create a sidebar manually
|
// But you can create a sidebar manually
|
||||||
/*
|
/*
|
||||||
tutorialSidebar: [
|
tutorialSidebar: [
|
||||||
|
'intro',
|
||||||
|
'hello',
|
||||||
{
|
{
|
||||||
type: 'category',
|
type: 'category',
|
||||||
label: 'Tutorial',
|
label: 'Tutorial',
|
||||||
items: ['hello'],
|
items: ['tutorial-basics/create-a-document'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -14,7 +14,9 @@ Anything **unclear** or **buggy** in this tutorial? [Please report it!](https://
|
||||||
|
|
||||||
## What's next?
|
## What's next?
|
||||||
|
|
||||||
- Read the [official documentation](https://docusaurus.io/).
|
- Read the [official documentation](https://docusaurus.io/)
|
||||||
|
- Modify your site configuration with [`docusaurus.config.js`](https://docusaurus.io/docs/api/docusaurus-config)
|
||||||
|
- Add navbar and footer items with [`themeConfig`](https://docusaurus.io/docs/api/themes/configuration)
|
||||||
- Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout)
|
- Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout)
|
||||||
- Add a [search bar](https://docusaurus.io/docs/search)
|
- Add a [search bar](https://docusaurus.io/docs/search)
|
||||||
- Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase)
|
- Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase)
|
||||||
|
|
|
@ -44,11 +44,13 @@ It is also possible to create your sidebar explicitly in `sidebars.js`:
|
||||||
```js title="sidebars.js"
|
```js title="sidebars.js"
|
||||||
module.exports = {
|
module.exports = {
|
||||||
tutorialSidebar: [
|
tutorialSidebar: [
|
||||||
|
'intro',
|
||||||
|
// highlight-next-line
|
||||||
|
'hello',
|
||||||
{
|
{
|
||||||
type: 'category',
|
type: 'category',
|
||||||
label: 'Tutorial',
|
label: 'Tutorial',
|
||||||
// highlight-next-line
|
items: ['tutorial-basics/create-a-document'],
|
||||||
items: ['hello'],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,10 +19,12 @@ const sidebars = {
|
||||||
// But you can create a sidebar manually
|
// But you can create a sidebar manually
|
||||||
/*
|
/*
|
||||||
tutorialSidebar: [
|
tutorialSidebar: [
|
||||||
|
'intro',
|
||||||
|
'hello',
|
||||||
{
|
{
|
||||||
type: 'category',
|
type: 'category',
|
||||||
label: 'Tutorial',
|
label: 'Tutorial',
|
||||||
items: ['hello'],
|
items: ['tutorial-basics/create-a-document'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -36,7 +36,6 @@
|
||||||
"webpack": "^5.73.0"
|
"webpack": "^5.73.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/types": "2.0.0-beta.21",
|
|
||||||
"escape-string-regexp": "^4.0.0"
|
"escape-string-regexp": "^4.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|
|
@ -52,7 +52,6 @@
|
||||||
"webpack": "^5.73.0"
|
"webpack": "^5.73.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/types": "2.0.0-beta.21",
|
|
||||||
"@types/js-yaml": "^4.0.5",
|
"@types/js-yaml": "^4.0.5",
|
||||||
"@types/picomatch": "^2.3.0",
|
"@types/picomatch": "^2.3.0",
|
||||||
"commander": "^5.1.0",
|
"commander": "^5.1.0",
|
||||||
|
|
|
@ -901,6 +901,7 @@ exports[`simple website content: data 1`] = `
|
||||||
"label": "Next",
|
"label": "Next",
|
||||||
"banner": null,
|
"banner": null,
|
||||||
"badge": false,
|
"badge": false,
|
||||||
|
"noIndex": false,
|
||||||
"className": "docs-version-current",
|
"className": "docs-version-current",
|
||||||
"isLast": true,
|
"isLast": true,
|
||||||
"docsSidebars": {
|
"docsSidebars": {
|
||||||
|
@ -2608,6 +2609,7 @@ exports[`versioned website (community) content: data 1`] = `
|
||||||
"label": "1.0.0",
|
"label": "1.0.0",
|
||||||
"banner": null,
|
"banner": null,
|
||||||
"badge": true,
|
"badge": true,
|
||||||
|
"noIndex": false,
|
||||||
"className": "docs-version-1.0.0",
|
"className": "docs-version-1.0.0",
|
||||||
"isLast": true,
|
"isLast": true,
|
||||||
"docsSidebars": {
|
"docsSidebars": {
|
||||||
|
@ -2635,6 +2637,7 @@ exports[`versioned website (community) content: data 1`] = `
|
||||||
"label": "Next",
|
"label": "Next",
|
||||||
"banner": "unreleased",
|
"banner": "unreleased",
|
||||||
"badge": true,
|
"badge": true,
|
||||||
|
"noIndex": false,
|
||||||
"className": "docs-version-current",
|
"className": "docs-version-current",
|
||||||
"isLast": false,
|
"isLast": false,
|
||||||
"docsSidebars": {
|
"docsSidebars": {
|
||||||
|
@ -3477,6 +3480,7 @@ exports[`versioned website content: data 1`] = `
|
||||||
"label": "1.0.0",
|
"label": "1.0.0",
|
||||||
"banner": "unmaintained",
|
"banner": "unmaintained",
|
||||||
"badge": true,
|
"badge": true,
|
||||||
|
"noIndex": false,
|
||||||
"className": "docs-version-1.0.0",
|
"className": "docs-version-1.0.0",
|
||||||
"isLast": false,
|
"isLast": false,
|
||||||
"docsSidebars": {
|
"docsSidebars": {
|
||||||
|
@ -3544,6 +3548,7 @@ exports[`versioned website content: data 1`] = `
|
||||||
"label": "1.0.1",
|
"label": "1.0.1",
|
||||||
"banner": null,
|
"banner": null,
|
||||||
"badge": true,
|
"badge": true,
|
||||||
|
"noIndex": true,
|
||||||
"className": "docs-version-1.0.1",
|
"className": "docs-version-1.0.1",
|
||||||
"isLast": true,
|
"isLast": true,
|
||||||
"docsSidebars": {
|
"docsSidebars": {
|
||||||
|
@ -3599,6 +3604,7 @@ exports[`versioned website content: data 1`] = `
|
||||||
"label": "Next",
|
"label": "Next",
|
||||||
"banner": "unreleased",
|
"banner": "unreleased",
|
||||||
"badge": true,
|
"badge": true,
|
||||||
|
"noIndex": false,
|
||||||
"className": "docs-version-current",
|
"className": "docs-version-current",
|
||||||
"isLast": false,
|
"isLast": false,
|
||||||
"docsSidebars": {
|
"docsSidebars": {
|
||||||
|
@ -3674,6 +3680,7 @@ exports[`versioned website content: data 1`] = `
|
||||||
"label": "withSlugs",
|
"label": "withSlugs",
|
||||||
"banner": "unmaintained",
|
"banner": "unmaintained",
|
||||||
"badge": true,
|
"badge": true,
|
||||||
|
"noIndex": false,
|
||||||
"className": "docs-version-withSlugs",
|
"className": "docs-version-withSlugs",
|
||||||
"isLast": false,
|
"isLast": false,
|
||||||
"docsSidebars": {
|
"docsSidebars": {
|
||||||
|
|
|
@ -362,6 +362,11 @@ describe('versioned website', () => {
|
||||||
options: {
|
options: {
|
||||||
routeBasePath,
|
routeBasePath,
|
||||||
sidebarPath,
|
sidebarPath,
|
||||||
|
versions: {
|
||||||
|
'1.0.1': {
|
||||||
|
noIndex: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const plugin = await pluginContentDocs(context, options);
|
const plugin = await pluginContentDocs(context, options);
|
||||||
|
|
|
@ -76,6 +76,7 @@ describe('normalizeDocsPluginOptions', () => {
|
||||||
version1: {
|
version1: {
|
||||||
path: 'hello',
|
path: 'hello',
|
||||||
label: 'world',
|
label: 'world',
|
||||||
|
noIndex: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
sidebarCollapsible: false,
|
sidebarCollapsible: false,
|
||||||
|
|
|
@ -59,6 +59,7 @@ const VersionOptionsSchema = Joi.object({
|
||||||
banner: Joi.string().equal('none', 'unreleased', 'unmaintained').optional(),
|
banner: Joi.string().equal('none', 'unreleased', 'unmaintained').optional(),
|
||||||
badge: Joi.boolean().optional(),
|
badge: Joi.boolean().optional(),
|
||||||
className: Joi.string().optional(),
|
className: Joi.string().optional(),
|
||||||
|
noIndex: Joi.boolean().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const VersionsOptionsSchema = Joi.object()
|
const VersionsOptionsSchema = Joi.object()
|
||||||
|
|
|
@ -125,6 +125,25 @@ declare module '@docusaurus/plugin-content-docs' {
|
||||||
// TODO support custom version banner?
|
// TODO support custom version banner?
|
||||||
// {type: "error", content: "html content"}
|
// {type: "error", content: "html content"}
|
||||||
export type VersionBanner = 'unreleased' | 'unmaintained';
|
export type VersionBanner = 'unreleased' | 'unmaintained';
|
||||||
|
|
||||||
|
export type VersionOptions = {
|
||||||
|
/**
|
||||||
|
* The base path of the version, will be appended to `baseUrl` +
|
||||||
|
* `routeBasePath`.
|
||||||
|
*/
|
||||||
|
path?: string;
|
||||||
|
/** The label of the version to be used in badges, dropdowns, etc. */
|
||||||
|
label?: string;
|
||||||
|
/** The banner to show at the top of a doc of that version. */
|
||||||
|
banner?: 'none' | VersionBanner;
|
||||||
|
/** Show a badge with the version label at the top of each doc. */
|
||||||
|
badge?: boolean;
|
||||||
|
/** Prevents search engines from indexing this version */
|
||||||
|
noIndex?: boolean;
|
||||||
|
/** Add a custom class name to the <html> element of each doc. */
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type VersionsOptions = {
|
export type VersionsOptions = {
|
||||||
/**
|
/**
|
||||||
* The version navigated to in priority and displayed by default for docs
|
* The version navigated to in priority and displayed by default for docs
|
||||||
|
@ -144,23 +163,7 @@ declare module '@docusaurus/plugin-content-docs' {
|
||||||
/** Include the current version of your docs. */
|
/** Include the current version of your docs. */
|
||||||
includeCurrentVersion: boolean;
|
includeCurrentVersion: boolean;
|
||||||
/** Independent customization of each version's properties. */
|
/** Independent customization of each version's properties. */
|
||||||
versions: {
|
versions: {[versionName: string]: VersionOptions};
|
||||||
[versionName: string]: {
|
|
||||||
/**
|
|
||||||
* The base path of the version, will be appended to `baseUrl` +
|
|
||||||
* `routeBasePath`.
|
|
||||||
*/
|
|
||||||
path?: string;
|
|
||||||
/** The label of the version to be used in badges, dropdowns, etc. */
|
|
||||||
label?: string;
|
|
||||||
/** The banner to show at the top of a doc of that version. */
|
|
||||||
banner?: 'none' | VersionBanner;
|
|
||||||
/** Show a badge with the version label at the top of each doc. */
|
|
||||||
badge?: boolean;
|
|
||||||
/** Add a custom class name to the <html> element of each doc. */
|
|
||||||
className?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
export type SidebarOptions = {
|
export type SidebarOptions = {
|
||||||
/**
|
/**
|
||||||
|
@ -263,6 +266,8 @@ declare module '@docusaurus/plugin-content-docs' {
|
||||||
banner: VersionBanner | null;
|
banner: VersionBanner | null;
|
||||||
/** Show a badge with the version label at the top of each doc. */
|
/** Show a badge with the version label at the top of each doc. */
|
||||||
badge: boolean;
|
badge: boolean;
|
||||||
|
/** Prevents search engines from indexing this version */
|
||||||
|
noIndex: boolean;
|
||||||
/** Add a custom class name to the <html> element of each doc. */
|
/** Add a custom class name to the <html> element of each doc. */
|
||||||
className: string;
|
className: string;
|
||||||
/**
|
/**
|
||||||
|
@ -500,7 +505,7 @@ declare module '@docusaurus/plugin-content-docs' {
|
||||||
|
|
||||||
export type PropVersionMetadata = Pick<
|
export type PropVersionMetadata = Pick<
|
||||||
VersionMetadata,
|
VersionMetadata,
|
||||||
'label' | 'banner' | 'badge' | 'className' | 'isLast'
|
'label' | 'banner' | 'badge' | 'className' | 'isLast' | 'noIndex'
|
||||||
> & {
|
> & {
|
||||||
/** ID of the docs plugin this version belongs to. */
|
/** ID of the docs plugin this version belongs to. */
|
||||||
pluginId: string;
|
pluginId: string;
|
||||||
|
|
|
@ -142,6 +142,7 @@ export function toVersionMetadataProp(
|
||||||
label: loadedVersion.label,
|
label: loadedVersion.label,
|
||||||
banner: loadedVersion.banner,
|
banner: loadedVersion.banner,
|
||||||
badge: loadedVersion.badge,
|
badge: loadedVersion.badge,
|
||||||
|
noIndex: loadedVersion.noIndex,
|
||||||
className: loadedVersion.className,
|
className: loadedVersion.className,
|
||||||
isLast: loadedVersion.isLast,
|
isLast: loadedVersion.isLast,
|
||||||
docsSidebars: toSidebarsProp(loadedVersion),
|
docsSidebars: toSidebarsProp(loadedVersion),
|
||||||
|
|
|
@ -44,6 +44,7 @@ export type SidebarItemLink = SidebarItemBase & {
|
||||||
type: 'link';
|
type: 'link';
|
||||||
href: string;
|
href: string;
|
||||||
label: string;
|
label: string;
|
||||||
|
autoAddBaseUrl?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SidebarItemAutogenerated = SidebarItemBase & {
|
export type SidebarItemAutogenerated = SidebarItemBase & {
|
||||||
|
|
|
@ -59,6 +59,7 @@ const sidebarItemHtmlSchema = sidebarItemBaseSchema.append<SidebarItemHtml>({
|
||||||
const sidebarItemLinkSchema = sidebarItemBaseSchema.append<SidebarItemLink>({
|
const sidebarItemLinkSchema = sidebarItemBaseSchema.append<SidebarItemLink>({
|
||||||
type: 'link',
|
type: 'link',
|
||||||
href: URISchema.required(),
|
href: URISchema.required(),
|
||||||
|
autoAddBaseUrl: Joi.boolean(),
|
||||||
label: Joi.string()
|
label: Joi.string()
|
||||||
.required()
|
.required()
|
||||||
.messages({'any.unknown': '"label" must be a string'}),
|
.messages({'any.unknown': '"label" must be a string'}),
|
||||||
|
|
|
@ -56,6 +56,7 @@ describe('readVersionsMetadata', () => {
|
||||||
path: '/docs',
|
path: '/docs',
|
||||||
banner: null,
|
banner: null,
|
||||||
badge: false,
|
badge: false,
|
||||||
|
noIndex: false,
|
||||||
className: 'docs-version-current',
|
className: 'docs-version-current',
|
||||||
};
|
};
|
||||||
return {simpleSiteDir, defaultOptions, defaultContext, vCurrent};
|
return {simpleSiteDir, defaultOptions, defaultContext, vCurrent};
|
||||||
|
@ -218,6 +219,7 @@ describe('readVersionsMetadata', () => {
|
||||||
path: '/docs/next',
|
path: '/docs/next',
|
||||||
banner: 'unreleased',
|
banner: 'unreleased',
|
||||||
badge: true,
|
badge: true,
|
||||||
|
noIndex: false,
|
||||||
className: 'docs-version-current',
|
className: 'docs-version-current',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -242,6 +244,7 @@ describe('readVersionsMetadata', () => {
|
||||||
path: '/docs',
|
path: '/docs',
|
||||||
banner: null,
|
banner: null,
|
||||||
badge: true,
|
badge: true,
|
||||||
|
noIndex: false,
|
||||||
className: 'docs-version-1.0.1',
|
className: 'docs-version-1.0.1',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -266,6 +269,7 @@ describe('readVersionsMetadata', () => {
|
||||||
path: '/docs/1.0.0',
|
path: '/docs/1.0.0',
|
||||||
banner: 'unmaintained',
|
banner: 'unmaintained',
|
||||||
badge: true,
|
badge: true,
|
||||||
|
noIndex: false,
|
||||||
className: 'docs-version-1.0.0',
|
className: 'docs-version-1.0.0',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -290,6 +294,7 @@ describe('readVersionsMetadata', () => {
|
||||||
path: '/docs/withSlugs',
|
path: '/docs/withSlugs',
|
||||||
banner: 'unmaintained',
|
banner: 'unmaintained',
|
||||||
badge: true,
|
badge: true,
|
||||||
|
noIndex: false,
|
||||||
className: 'docs-version-withSlugs',
|
className: 'docs-version-withSlugs',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -657,6 +662,7 @@ describe('readVersionsMetadata', () => {
|
||||||
path: '/communityBasePath/next',
|
path: '/communityBasePath/next',
|
||||||
banner: 'unreleased',
|
banner: 'unreleased',
|
||||||
badge: true,
|
badge: true,
|
||||||
|
noIndex: false,
|
||||||
className: 'docs-version-current',
|
className: 'docs-version-current',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -681,6 +687,7 @@ describe('readVersionsMetadata', () => {
|
||||||
path: '/communityBasePath',
|
path: '/communityBasePath',
|
||||||
banner: null,
|
banner: null,
|
||||||
badge: true,
|
badge: true,
|
||||||
|
noIndex: false,
|
||||||
className: 'docs-version-1.0.0',
|
className: 'docs-version-1.0.0',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,13 @@ export function getVersionBadge({
|
||||||
return options.versions[versionName]?.badge ?? defaultVersionBadge;
|
return options.versions[versionName]?.badge ?? defaultVersionBadge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getVersionNoIndex({
|
||||||
|
versionName,
|
||||||
|
options,
|
||||||
|
}: VersionContext): VersionMetadata['noIndex'] {
|
||||||
|
return options.versions[versionName]?.noIndex ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
function getVersionClassName({
|
function getVersionClassName({
|
||||||
versionName,
|
versionName,
|
||||||
options,
|
options,
|
||||||
|
@ -179,6 +186,7 @@ async function createVersionMetadata(
|
||||||
label: getVersionLabel(context),
|
label: getVersionLabel(context),
|
||||||
banner: getVersionBanner(context),
|
banner: getVersionBanner(context),
|
||||||
badge: getVersionBadge(context),
|
badge: getVersionBadge(context),
|
||||||
|
noIndex: getVersionNoIndex(context),
|
||||||
className: getVersionClassName(context),
|
className: getVersionClassName(context),
|
||||||
path: routePath,
|
path: routePath,
|
||||||
tagsPath: normalizeUrl([routePath, options.tagsBasePath]),
|
tagsPath: normalizeUrl([routePath, options.tagsBasePath]),
|
||||||
|
|
|
@ -27,9 +27,6 @@
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"webpack": "^5.73.0"
|
"webpack": "^5.73.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
|
||||||
"@docusaurus/types": "2.0.0-beta.21"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
|
|
|
@ -27,9 +27,6 @@
|
||||||
"react-json-view": "^1.21.3",
|
"react-json-view": "^1.21.3",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
|
||||||
"@docusaurus/types": "2.0.0-beta.21"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
|
|
|
@ -23,9 +23,6 @@
|
||||||
"@docusaurus/utils-validation": "2.0.1",
|
"@docusaurus/utils-validation": "2.0.1",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
|
||||||
"@docusaurus/types": "2.0.0-beta.21"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
|
|
|
@ -23,9 +23,6 @@
|
||||||
"@docusaurus/utils-validation": "2.0.1",
|
"@docusaurus/utils-validation": "2.0.1",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
|
||||||
"@docusaurus/types": "2.0.0-beta.21"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "2.0.1",
|
"@docusaurus/module-type-aliases": "2.0.1",
|
||||||
"@docusaurus/types": "2.0.0-beta.21",
|
|
||||||
"fs-extra": "^10.1.0"
|
"fs-extra": "^10.1.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|
|
@ -28,9 +28,6 @@
|
||||||
"sitemap": "^7.1.1",
|
"sitemap": "^7.1.1",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
|
||||||
"@docusaurus/types": "2.0.0-beta.21"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
"react-dom": "^16.8.4 || ^17.0.0"
|
"react-dom": "^16.8.4 || ^17.0.0"
|
||||||
|
|
|
@ -158,7 +158,10 @@ describe('createSitemap', () => {
|
||||||
meta: {
|
meta: {
|
||||||
// @ts-expect-error: bad lib def
|
// @ts-expect-error: bad lib def
|
||||||
toComponent: () => [
|
toComponent: () => [
|
||||||
React.createElement('meta', {name: 'robots', content: 'noindex'}),
|
React.createElement('meta', {
|
||||||
|
name: 'robots',
|
||||||
|
content: 'NoFolloW, NoiNDeX',
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -13,6 +13,40 @@ import type {DocusaurusConfig} from '@docusaurus/types';
|
||||||
import type {HelmetServerState} from 'react-helmet-async';
|
import type {HelmetServerState} from 'react-helmet-async';
|
||||||
import type {PluginOptions} from './options';
|
import type {PluginOptions} from './options';
|
||||||
|
|
||||||
|
function isNoIndexMetaRoute({
|
||||||
|
head,
|
||||||
|
route,
|
||||||
|
}: {
|
||||||
|
head: {[location: string]: HelmetServerState};
|
||||||
|
route: string;
|
||||||
|
}) {
|
||||||
|
const isNoIndexMetaTag = ({
|
||||||
|
name,
|
||||||
|
content,
|
||||||
|
}: {
|
||||||
|
name?: string;
|
||||||
|
content?: string;
|
||||||
|
}): boolean => {
|
||||||
|
if (!name || !content) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
// meta name is not case-sensitive
|
||||||
|
name.toLowerCase() === 'robots' &&
|
||||||
|
// Robots directives are not case-sensitive
|
||||||
|
content.toLowerCase().includes('noindex')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://github.com/staylor/react-helmet-async/pull/167
|
||||||
|
const meta = head[route]?.meta.toComponent() as unknown as
|
||||||
|
| ReactElement<{name?: string; content?: string}>[]
|
||||||
|
| undefined;
|
||||||
|
return meta?.some((tag) =>
|
||||||
|
isNoIndexMetaTag({name: tag.props.name, content: tag.props.content}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default async function createSitemap(
|
export default async function createSitemap(
|
||||||
siteConfig: DocusaurusConfig,
|
siteConfig: DocusaurusConfig,
|
||||||
routesPaths: string[],
|
routesPaths: string[],
|
||||||
|
@ -27,18 +61,15 @@ export default async function createSitemap(
|
||||||
|
|
||||||
const ignoreMatcher = createMatcher(ignorePatterns);
|
const ignoreMatcher = createMatcher(ignorePatterns);
|
||||||
|
|
||||||
const includedRoutes = routesPaths.filter((route) => {
|
function isRouteExcluded(route: string) {
|
||||||
if (route.endsWith('404.html') || ignoreMatcher(route)) {
|
return (
|
||||||
return false;
|
route.endsWith('404.html') ||
|
||||||
}
|
ignoreMatcher(route) ||
|
||||||
// https://github.com/staylor/react-helmet-async/pull/167
|
isNoIndexMetaRoute({head, route})
|
||||||
const meta = head[route]?.meta.toComponent() as unknown as
|
|
||||||
| ReactElement<{name?: string; content?: string}>[]
|
|
||||||
| undefined;
|
|
||||||
return !meta?.some(
|
|
||||||
(tag) => tag.props.name === 'robots' && tag.props.content === 'noindex',
|
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
const includedRoutes = routesPaths.filter((route) => !isRouteExcluded(route));
|
||||||
|
|
||||||
if (includedRoutes.length === 0) {
|
if (includedRoutes.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -87,7 +87,7 @@ export default function preset(
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unrecognized keys ${Object.keys(rest).join(
|
`Unrecognized keys ${Object.keys(rest).join(
|
||||||
', ',
|
', ',
|
||||||
)} found in preset-classic configuration. The allowed keys are debug, docs, blog, pages, sitemap, theme, googleAnalytics, gtag. Check the documentation: https://docusaurus.io/docs/presets#docusauruspreset-classic for more information on how to configure individual plugins.`,
|
)} found in preset-classic configuration. The allowed keys are debug, docs, blog, pages, sitemap, theme, googleAnalytics, gtag. Check the documentation: https://docusaurus.io/docs/using-plugins#docusauruspreset-classic for more information on how to configure individual plugins.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,8 +47,6 @@
|
||||||
"utility-types": "^3.10.0"
|
"utility-types": "^3.10.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "2.0.0-beta.21",
|
|
||||||
"@docusaurus/types": "2.0.0-beta.21",
|
|
||||||
"@types/mdx-js__react": "^1.5.5",
|
"@types/mdx-js__react": "^1.5.5",
|
||||||
"@types/nprogress": "^0.2.0",
|
"@types/nprogress": "^0.2.0",
|
||||||
"@types/prismjs": "^1.26.0",
|
"@types/prismjs": "^1.26.0",
|
||||||
|
|
|
@ -28,6 +28,14 @@ export default function getSwizzleConfig(): SwizzleConfig {
|
||||||
description:
|
description:
|
||||||
'The color mode toggle to switch between light and dark mode.',
|
'The color mode toggle to switch between light and dark mode.',
|
||||||
},
|
},
|
||||||
|
DocCardList: {
|
||||||
|
actions: {
|
||||||
|
eject: 'safe',
|
||||||
|
wrap: 'safe',
|
||||||
|
},
|
||||||
|
description:
|
||||||
|
'The component responsible for rendering a list of sidebar items cards.\nNotable used on the category generated-index pages.',
|
||||||
|
},
|
||||||
DocSidebar: {
|
DocSidebar: {
|
||||||
actions: {
|
actions: {
|
||||||
eject: 'unsafe', // Too much technical code in sidebar, not very safe atm
|
eject: 'unsafe', // Too much technical code in sidebar, not very safe atm
|
||||||
|
|
|
@ -55,6 +55,22 @@ declare module '@theme/AnnouncementBar' {
|
||||||
export default function AnnouncementBar(): JSX.Element | null;
|
export default function AnnouncementBar(): JSX.Element | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module '@theme/AnnouncementBar/Content' {
|
||||||
|
import type {ComponentProps} from 'react';
|
||||||
|
|
||||||
|
export interface Props extends ComponentProps<'div'> {}
|
||||||
|
|
||||||
|
export default function AnnouncementBarContent(props: Props): JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@theme/AnnouncementBar/CloseButton' {
|
||||||
|
import type {ComponentProps} from 'react';
|
||||||
|
|
||||||
|
export interface Props extends ComponentProps<'button'> {}
|
||||||
|
|
||||||
|
export default function AnnouncementBarCloseButton(props: Props): JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
declare module '@theme/BackToTopButton' {
|
declare module '@theme/BackToTopButton' {
|
||||||
export default function BackToTopButton(): JSX.Element;
|
export default function BackToTopButton(): JSX.Element;
|
||||||
}
|
}
|
||||||
|
@ -320,7 +336,7 @@ declare module '@theme/DocCardList' {
|
||||||
import type {PropSidebarItem} from '@docusaurus/plugin-content-docs';
|
import type {PropSidebarItem} from '@docusaurus/plugin-content-docs';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly items: PropSidebarItem[];
|
readonly items?: PropSidebarItem[];
|
||||||
readonly className?: string;
|
readonly className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/**
|
||||||
|
* 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 React from 'react';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import {translate} from '@docusaurus/Translate';
|
||||||
|
import IconClose from '@theme/Icon/Close';
|
||||||
|
import type {Props} from '@theme/AnnouncementBar/CloseButton';
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
|
export default function AnnouncementBarCloseButton(
|
||||||
|
props: Props,
|
||||||
|
): JSX.Element | null {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label={translate({
|
||||||
|
id: 'theme.AnnouncementBar.closeButtonAriaLabel',
|
||||||
|
message: 'Close',
|
||||||
|
description: 'The ARIA label for close button of announcement bar',
|
||||||
|
})}
|
||||||
|
{...props}
|
||||||
|
className={clsx('clean-btn close', styles.closeButton, props.className)}>
|
||||||
|
<IconClose width={14} height={14} strokeWidth={3.1} />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.closeButton {
|
||||||
|
padding: 0;
|
||||||
|
line-height: 0;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* 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 React from 'react';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import {useThemeConfig} from '@docusaurus/theme-common';
|
||||||
|
import type {Props} from '@theme/AnnouncementBar/Content';
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
|
export default function AnnouncementBarContent(
|
||||||
|
props: Props,
|
||||||
|
): JSX.Element | null {
|
||||||
|
const {announcementBar} = useThemeConfig();
|
||||||
|
const {content} = announcementBar!;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
{...props}
|
||||||
|
className={clsx(styles.content, props.className)}
|
||||||
|
// Developer provided the HTML, so assume it's safe.
|
||||||
|
// eslint-disable-next-line react/no-danger
|
||||||
|
dangerouslySetInnerHTML={{__html: content}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.content {
|
||||||
|
font-size: 85%;
|
||||||
|
text-align: center;
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
|
@ -6,49 +6,33 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import clsx from 'clsx';
|
|
||||||
import {useThemeConfig} from '@docusaurus/theme-common';
|
import {useThemeConfig} from '@docusaurus/theme-common';
|
||||||
import {useAnnouncementBar} from '@docusaurus/theme-common/internal';
|
import {useAnnouncementBar} from '@docusaurus/theme-common/internal';
|
||||||
import {translate} from '@docusaurus/Translate';
|
import AnnouncementBarCloseButton from '@theme/AnnouncementBar/CloseButton';
|
||||||
import IconClose from '@theme/Icon/Close';
|
import AnnouncementBarContent from '@theme/AnnouncementBar/Content';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
export default function AnnouncementBar(): JSX.Element | null {
|
export default function AnnouncementBar(): JSX.Element | null {
|
||||||
const {isActive, close} = useAnnouncementBar();
|
|
||||||
const {announcementBar} = useThemeConfig();
|
const {announcementBar} = useThemeConfig();
|
||||||
|
const {isActive, close} = useAnnouncementBar();
|
||||||
if (!isActive) {
|
if (!isActive) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const {backgroundColor, textColor, isCloseable} = announcementBar!;
|
||||||
const {content, backgroundColor, textColor, isCloseable} = announcementBar!;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={styles.announcementBar}
|
className={styles.announcementBar}
|
||||||
style={{backgroundColor, color: textColor}}
|
style={{backgroundColor, color: textColor}}
|
||||||
role="banner">
|
role="banner">
|
||||||
{isCloseable && <div className={styles.announcementBarPlaceholder} />}
|
{isCloseable && <div className={styles.announcementBarPlaceholder} />}
|
||||||
<div
|
<AnnouncementBarContent className={styles.announcementBarContent} />
|
||||||
className={styles.announcementBarContent}
|
{isCloseable && (
|
||||||
// Developer provided the HTML, so assume it's safe.
|
<AnnouncementBarCloseButton
|
||||||
// eslint-disable-next-line react/no-danger
|
|
||||||
dangerouslySetInnerHTML={{__html: content}}
|
|
||||||
/>
|
|
||||||
{isCloseable ? (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={clsx('clean-btn close', styles.announcementBarClose)}
|
|
||||||
onClick={close}
|
onClick={close}
|
||||||
aria-label={translate({
|
className={styles.announcementBarClose}
|
||||||
id: 'theme.AnnouncementBar.closeButtonAriaLabel',
|
/>
|
||||||
message: 'Close',
|
)}
|
||||||
description: 'The ARIA label for close button of announcement bar',
|
|
||||||
})}>
|
|
||||||
<IconClose width={14} height={14} strokeWidth={3.1} />
|
|
||||||
</button>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
height: var(--docusaurus-announcement-bar-height);
|
height: var(--docusaurus-announcement-bar-height);
|
||||||
background-color: var(--ifm-color-white);
|
background-color: var(--ifm-color-white);
|
||||||
color: var(--ifm-color-black);
|
color: var(--ifm-color-black);
|
||||||
border-bottom: 1px solid var(--ifm-color-emphasis-100);
|
box-shadow: var(--ifm-global-shadow-lw);
|
||||||
|
z-index: calc(var(--ifm-z-index-fixed) + 1); /* just above the navbar */
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-announcement-bar-initially-dismissed='true'] .announcementBar {
|
html[data-announcement-bar-initially-dismissed='true'] .announcementBar {
|
||||||
|
@ -29,15 +30,10 @@ html[data-announcement-bar-initially-dismissed='true'] .announcementBar {
|
||||||
.announcementBarClose {
|
.announcementBarClose {
|
||||||
flex: 0 0 30px;
|
flex: 0 0 30px;
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
padding: 0;
|
|
||||||
line-height: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.announcementBarContent {
|
.announcementBarContent {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
font-size: 85%;
|
|
||||||
text-align: center;
|
|
||||||
padding: 5px 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
|
@ -46,11 +42,6 @@ html[data-announcement-bar-initially-dismissed='true'] .announcementBar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.announcementBarContent a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 997px) {
|
@media (min-width: 997px) {
|
||||||
:root {
|
:root {
|
||||||
--docusaurus-announcement-bar-height: 30px;
|
--docusaurus-announcement-bar-height: 30px;
|
||||||
|
|
|
@ -35,6 +35,7 @@ the background in custom CSS file due bug https://github.com/facebook/docusaurus
|
||||||
left: 0;
|
left: 0;
|
||||||
padding: 0 var(--ifm-pre-padding);
|
padding: 0 var(--ifm-pre-padding);
|
||||||
background: var(--ifm-pre-background);
|
background: var(--ifm-pre-background);
|
||||||
|
overflow-wrap: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.codeLineNumber::before {
|
.codeLineNumber::before {
|
||||||
|
|
|
@ -7,25 +7,27 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import {findFirstCategoryLink} from '@docusaurus/theme-common/internal';
|
import {
|
||||||
|
useCurrentSidebarCategory,
|
||||||
|
filterDocCardListItems,
|
||||||
|
} from '@docusaurus/theme-common';
|
||||||
import DocCard from '@theme/DocCard';
|
import DocCard from '@theme/DocCard';
|
||||||
import type {Props} from '@theme/DocCardList';
|
import type {Props} from '@theme/DocCardList';
|
||||||
import type {PropSidebarItem} from '@docusaurus/plugin-content-docs';
|
|
||||||
|
|
||||||
// Filter categories that don't have a link.
|
function DocCardListForCurrentSidebarCategory({className}: Props) {
|
||||||
function filterItems(items: PropSidebarItem[]): PropSidebarItem[] {
|
const category = useCurrentSidebarCategory();
|
||||||
return items.filter((item) => {
|
return <DocCardList items={category.items} className={className} />;
|
||||||
if (item.type === 'category') {
|
|
||||||
return !!findFirstCategoryLink(item);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function DocCardList({items, className}: Props): JSX.Element {
|
export default function DocCardList(props: Props): JSX.Element {
|
||||||
|
const {items, className} = props;
|
||||||
|
if (!items) {
|
||||||
|
return <DocCardListForCurrentSidebarCategory {...props} />;
|
||||||
|
}
|
||||||
|
const filteredItems = filterDocCardListItems(items);
|
||||||
return (
|
return (
|
||||||
<section className={clsx('row', className)}>
|
<section className={clsx('row', className)}>
|
||||||
{filterItems(items).map((item, index) => (
|
{filteredItems.map((item, index) => (
|
||||||
<article key={index} className="col col--6 margin-bottom--lg">
|
<article key={index} className="col col--6 margin-bottom--lg">
|
||||||
<DocCard item={item} />
|
<DocCard item={item} />
|
||||||
</article>
|
</article>
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import {HtmlClassNameProvider, ThemeClassNames} from '@docusaurus/theme-common';
|
import {
|
||||||
|
HtmlClassNameProvider,
|
||||||
|
ThemeClassNames,
|
||||||
|
PageMetadata,
|
||||||
|
} from '@docusaurus/theme-common';
|
||||||
import {
|
import {
|
||||||
docVersionSearchTag,
|
docVersionSearchTag,
|
||||||
DocsSidebarProvider,
|
DocsSidebarProvider,
|
||||||
|
@ -19,13 +23,8 @@ import NotFound from '@theme/NotFound';
|
||||||
import SearchMetadata from '@theme/SearchMetadata';
|
import SearchMetadata from '@theme/SearchMetadata';
|
||||||
import type {Props} from '@theme/DocPage';
|
import type {Props} from '@theme/DocPage';
|
||||||
|
|
||||||
export default function DocPage(props: Props): JSX.Element {
|
function DocPageMetadata(props: Props): JSX.Element {
|
||||||
const {versionMetadata} = props;
|
const {versionMetadata} = props;
|
||||||
const currentDocRouteMetadata = useDocRouteMetadata(props);
|
|
||||||
if (!currentDocRouteMetadata) {
|
|
||||||
return <NotFound />;
|
|
||||||
}
|
|
||||||
const {docElement, sidebarName, sidebarItems} = currentDocRouteMetadata;
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SearchMetadata
|
<SearchMetadata
|
||||||
|
@ -35,6 +34,25 @@ export default function DocPage(props: Props): JSX.Element {
|
||||||
versionMetadata.version,
|
versionMetadata.version,
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<PageMetadata>
|
||||||
|
{versionMetadata.noIndex && (
|
||||||
|
<meta name="robots" content="noindex, nofollow" />
|
||||||
|
)}
|
||||||
|
</PageMetadata>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function DocPage(props: Props): JSX.Element {
|
||||||
|
const {versionMetadata} = props;
|
||||||
|
const currentDocRouteMetadata = useDocRouteMetadata(props);
|
||||||
|
if (!currentDocRouteMetadata) {
|
||||||
|
return <NotFound />;
|
||||||
|
}
|
||||||
|
const {docElement, sidebarName, sidebarItems} = currentDocRouteMetadata;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DocPageMetadata {...props} />
|
||||||
<HtmlClassNameProvider
|
<HtmlClassNameProvider
|
||||||
className={clsx(
|
className={clsx(
|
||||||
// TODO: it should be removed from here
|
// TODO: it should be removed from here
|
||||||
|
|
|
@ -136,7 +136,7 @@ export default function DocSidebarItemCategory({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
collapsible &&
|
collapsible &&
|
||||||
expandedItem &&
|
expandedItem != null &&
|
||||||
expandedItem !== index &&
|
expandedItem !== index &&
|
||||||
autoCollapseCategories
|
autoCollapseCategories
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ export default function DocSidebarItemLink({
|
||||||
index,
|
index,
|
||||||
...props
|
...props
|
||||||
}: Props): JSX.Element {
|
}: Props): JSX.Element {
|
||||||
const {href, label, className} = item;
|
const {href, label, className, autoAddBaseUrl} = item;
|
||||||
const isActive = isActiveSidebarItem(item, activePath);
|
const isActive = isActiveSidebarItem(item, activePath);
|
||||||
const isInternalLink = isInternalUrl(href);
|
const isInternalLink = isInternalUrl(href);
|
||||||
return (
|
return (
|
||||||
|
@ -44,6 +44,7 @@ export default function DocSidebarItemLink({
|
||||||
'menu__link--active': isActive,
|
'menu__link--active': isActive,
|
||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
|
autoAddBaseUrl={autoAddBaseUrl}
|
||||||
aria-current={isActive ? 'page' : undefined}
|
aria-current={isActive ? 'page' : undefined}
|
||||||
to={href}
|
to={href}
|
||||||
{...(isInternalLink && {
|
{...(isInternalLink && {
|
||||||
|
|
|
@ -34,6 +34,7 @@ export default function LocaleDropdownNavbarItem({
|
||||||
})}`;
|
})}`;
|
||||||
return {
|
return {
|
||||||
label: localeConfigs[locale]!.label,
|
label: localeConfigs[locale]!.label,
|
||||||
|
lang: localeConfigs[locale]!.htmlLang,
|
||||||
to,
|
to,
|
||||||
target: '_self',
|
target: '_self',
|
||||||
autoAddBaseUrl: false,
|
autoAddBaseUrl: false,
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Translate from '@docusaurus/Translate';
|
import Translate, {translate} from '@docusaurus/Translate';
|
||||||
import {useSkipToContent} from '@docusaurus/theme-common/internal';
|
import {useSkipToContent} from '@docusaurus/theme-common/internal';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
@ -14,7 +14,10 @@ import styles from './styles.module.css';
|
||||||
export default function SkipToContent(): JSX.Element {
|
export default function SkipToContent(): JSX.Element {
|
||||||
const {containerRef, handleSkip} = useSkipToContent();
|
const {containerRef, handleSkip} = useSkipToContent();
|
||||||
return (
|
return (
|
||||||
<div ref={containerRef} role="region">
|
<div
|
||||||
|
ref={containerRef}
|
||||||
|
role="region"
|
||||||
|
aria-label={translate({id: 'theme.common.skipToMainContent'})}>
|
||||||
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
||||||
<a href="#" className={styles.skipToContent} onClick={handleSkip}>
|
<a href="#" className={styles.skipToContent} onClick={handleSkip}>
|
||||||
<Translate
|
<Translate
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
.tagRegular {
|
.tagRegular {
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
padding: 0.3rem 0.5rem;
|
padding: 0.2rem 0.5rem 0.3rem;
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,10 @@ export {createStorageSlot, listStorageKeys} from './utils/storageUtils';
|
||||||
|
|
||||||
export {useContextualSearchFilters} from './utils/searchUtils';
|
export {useContextualSearchFilters} from './utils/searchUtils';
|
||||||
|
|
||||||
export {useCurrentSidebarCategory} from './utils/docsUtils';
|
export {
|
||||||
|
useCurrentSidebarCategory,
|
||||||
|
filterDocCardListItems,
|
||||||
|
} from './utils/docsUtils';
|
||||||
|
|
||||||
export {usePluralForm} from './utils/usePluralForm';
|
export {usePluralForm} from './utils/usePluralForm';
|
||||||
|
|
||||||
|
|
|
@ -441,26 +441,87 @@ describe('useCurrentSidebarCategory', () => {
|
||||||
</DocsSidebarProvider>
|
</DocsSidebarProvider>
|
||||||
),
|
),
|
||||||
}).result.current;
|
}).result.current;
|
||||||
it('works', () => {
|
|
||||||
const category: PropSidebarItemCategory = {
|
it('works for sidebar category', () => {
|
||||||
type: 'category',
|
const category: PropSidebarItemCategory = testCategory({
|
||||||
label: 'Category',
|
|
||||||
href: '/cat',
|
href: '/cat',
|
||||||
collapsible: true,
|
});
|
||||||
collapsed: false,
|
const sidebar: PropSidebar = [
|
||||||
items: [
|
testLink(),
|
||||||
{type: 'link', href: '/cat/foo', label: 'Foo'},
|
testLink(),
|
||||||
{type: 'link', href: '/cat/bar', label: 'Bar'},
|
|
||||||
{type: 'link', href: '/baz', label: 'Baz'},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
const mockUseCurrentSidebarCategory = createUseCurrentSidebarCategoryMock([
|
|
||||||
{type: 'link', href: '/cat/fake', label: 'Fake'},
|
|
||||||
category,
|
category,
|
||||||
]);
|
testCategory(),
|
||||||
|
];
|
||||||
|
|
||||||
|
const mockUseCurrentSidebarCategory =
|
||||||
|
createUseCurrentSidebarCategoryMock(sidebar);
|
||||||
|
|
||||||
expect(mockUseCurrentSidebarCategory('/cat')).toEqual(category);
|
expect(mockUseCurrentSidebarCategory('/cat')).toEqual(category);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('works for nested sidebar category', () => {
|
||||||
|
const category2: PropSidebarItemCategory = testCategory({
|
||||||
|
href: '/cat2',
|
||||||
|
});
|
||||||
|
const category1: PropSidebarItemCategory = testCategory({
|
||||||
|
href: '/cat1',
|
||||||
|
items: [testLink(), testLink(), category2, testCategory()],
|
||||||
|
});
|
||||||
|
const sidebar: PropSidebar = [
|
||||||
|
testLink(),
|
||||||
|
testLink(),
|
||||||
|
category1,
|
||||||
|
testCategory(),
|
||||||
|
];
|
||||||
|
|
||||||
|
const mockUseCurrentSidebarCategory =
|
||||||
|
createUseCurrentSidebarCategoryMock(sidebar);
|
||||||
|
|
||||||
|
expect(mockUseCurrentSidebarCategory('/cat2')).toEqual(category2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('works for category link item', () => {
|
||||||
|
const link = testLink({href: '/my/link/path'});
|
||||||
|
const category: PropSidebarItemCategory = testCategory({
|
||||||
|
href: '/cat1',
|
||||||
|
items: [testLink(), testLink(), link, testCategory()],
|
||||||
|
});
|
||||||
|
const sidebar: PropSidebar = [
|
||||||
|
testLink(),
|
||||||
|
testLink(),
|
||||||
|
category,
|
||||||
|
testCategory(),
|
||||||
|
];
|
||||||
|
|
||||||
|
const mockUseCurrentSidebarCategory =
|
||||||
|
createUseCurrentSidebarCategoryMock(sidebar);
|
||||||
|
|
||||||
|
expect(mockUseCurrentSidebarCategory('/my/link/path')).toEqual(category);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('works for nested category link item', () => {
|
||||||
|
const link = testLink({href: '/my/link/path'});
|
||||||
|
const category2: PropSidebarItemCategory = testCategory({
|
||||||
|
href: '/cat2',
|
||||||
|
items: [testLink(), testLink(), link, testCategory()],
|
||||||
|
});
|
||||||
|
const category1: PropSidebarItemCategory = testCategory({
|
||||||
|
href: '/cat1',
|
||||||
|
items: [testLink(), testLink(), category2, testCategory()],
|
||||||
|
});
|
||||||
|
const sidebar: PropSidebar = [
|
||||||
|
testLink(),
|
||||||
|
testLink(),
|
||||||
|
category1,
|
||||||
|
testCategory(),
|
||||||
|
];
|
||||||
|
|
||||||
|
const mockUseCurrentSidebarCategory =
|
||||||
|
createUseCurrentSidebarCategoryMock(sidebar);
|
||||||
|
|
||||||
|
expect(mockUseCurrentSidebarCategory('/my/link/path')).toEqual(category2);
|
||||||
|
});
|
||||||
|
|
||||||
it('throws for non-category index page', () => {
|
it('throws for non-category index page', () => {
|
||||||
const category: PropSidebarItemCategory = {
|
const category: PropSidebarItemCategory = {
|
||||||
type: 'category',
|
type: 'category',
|
||||||
|
|
|
@ -110,15 +110,18 @@ export function useCurrentSidebarCategory(): PropSidebarItemCategory {
|
||||||
if (!sidebar) {
|
if (!sidebar) {
|
||||||
throw new Error('Unexpected: cant find current sidebar in context');
|
throw new Error('Unexpected: cant find current sidebar in context');
|
||||||
}
|
}
|
||||||
const category = findSidebarCategory(sidebar.items, (item) =>
|
const categoryBreadcrumbs = getSidebarBreadcrumbs({
|
||||||
isSamePath(item.href, pathname),
|
sidebarItems: sidebar.items,
|
||||||
);
|
pathname,
|
||||||
if (!category) {
|
onlyCategories: true,
|
||||||
|
});
|
||||||
|
const deepestCategory = categoryBreadcrumbs.slice(-1)[0];
|
||||||
|
if (!deepestCategory) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`${pathname} is not associated with a category. useCurrentSidebarCategory() should only be used on category index pages.`,
|
`${pathname} is not associated with a category. useCurrentSidebarCategory() should only be used on category index pages.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return category;
|
return deepestCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isActive = (testedPath: string | undefined, activePath: string) =>
|
const isActive = (testedPath: string | undefined, activePath: string) =>
|
||||||
|
@ -149,6 +152,55 @@ export function isActiveSidebarItem(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSidebarBreadcrumbs(param: {
|
||||||
|
sidebarItems: PropSidebar;
|
||||||
|
pathname: string;
|
||||||
|
onlyCategories: true;
|
||||||
|
}): PropSidebarItemCategory[];
|
||||||
|
|
||||||
|
function getSidebarBreadcrumbs(param: {
|
||||||
|
sidebarItems: PropSidebar;
|
||||||
|
pathname: string;
|
||||||
|
}): PropSidebarBreadcrumbsItem[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the sidebar the breadcrumbs for a given pathname
|
||||||
|
* Ordered from top to bottom
|
||||||
|
*/
|
||||||
|
function getSidebarBreadcrumbs({
|
||||||
|
sidebarItems,
|
||||||
|
pathname,
|
||||||
|
onlyCategories = false,
|
||||||
|
}: {
|
||||||
|
sidebarItems: PropSidebar;
|
||||||
|
pathname: string;
|
||||||
|
onlyCategories?: boolean;
|
||||||
|
}): PropSidebarBreadcrumbsItem[] {
|
||||||
|
const breadcrumbs: PropSidebarBreadcrumbsItem[] = [];
|
||||||
|
|
||||||
|
function extract(items: PropSidebarItem[]) {
|
||||||
|
for (const item of items) {
|
||||||
|
if (
|
||||||
|
(item.type === 'category' &&
|
||||||
|
(isSamePath(item.href, pathname) || extract(item.items))) ||
|
||||||
|
(item.type === 'link' && isSamePath(item.href, pathname))
|
||||||
|
) {
|
||||||
|
const filtered = onlyCategories && item.type !== 'category';
|
||||||
|
if (!filtered) {
|
||||||
|
breadcrumbs.unshift(item);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
extract(sidebarItems);
|
||||||
|
|
||||||
|
return breadcrumbs;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the breadcrumbs of the current doc page, based on its sidebar location.
|
* Gets the breadcrumbs of the current doc page, based on its sidebar location.
|
||||||
* Returns `null` if there's no sidebar or breadcrumbs are disabled.
|
* Returns `null` if there's no sidebar or breadcrumbs are disabled.
|
||||||
|
@ -157,31 +209,10 @@ export function useSidebarBreadcrumbs(): PropSidebarBreadcrumbsItem[] | null {
|
||||||
const sidebar = useDocsSidebar();
|
const sidebar = useDocsSidebar();
|
||||||
const {pathname} = useLocation();
|
const {pathname} = useLocation();
|
||||||
const breadcrumbsOption = useActivePlugin()?.pluginData.breadcrumbs;
|
const breadcrumbsOption = useActivePlugin()?.pluginData.breadcrumbs;
|
||||||
|
|
||||||
if (breadcrumbsOption === false || !sidebar) {
|
if (breadcrumbsOption === false || !sidebar) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return getSidebarBreadcrumbs({sidebarItems: sidebar.items, pathname});
|
||||||
const breadcrumbs: PropSidebarBreadcrumbsItem[] = [];
|
|
||||||
|
|
||||||
function extract(items: PropSidebar) {
|
|
||||||
for (const item of items) {
|
|
||||||
if (
|
|
||||||
(item.type === 'category' &&
|
|
||||||
(isSamePath(item.href, pathname) || extract(item.items))) ||
|
|
||||||
(item.type === 'link' && isSamePath(item.href, pathname))
|
|
||||||
) {
|
|
||||||
breadcrumbs.push(item);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
extract(sidebar.items);
|
|
||||||
|
|
||||||
return breadcrumbs.reverse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -332,3 +363,18 @@ export function useDocRouteMetadata({
|
||||||
sidebarItems,
|
sidebarItems,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter categories that don't have a link.
|
||||||
|
* @param items
|
||||||
|
*/
|
||||||
|
export function filterDocCardListItems(
|
||||||
|
items: PropSidebarItem[],
|
||||||
|
): PropSidebarItem[] {
|
||||||
|
return items.filter((item) => {
|
||||||
|
if (item.type === 'category') {
|
||||||
|
return !!findFirstCategoryLink(item);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"theme.IdealImageMessage.404error": "404. Зображення не знайдено",
|
||||||
|
"theme.IdealImageMessage.error": "Помилка. Натисніть, щоб перезавантажити",
|
||||||
|
"theme.IdealImageMessage.load": "Натисніть, щоб завантажити {sizeMessage}",
|
||||||
|
"theme.IdealImageMessage.loading": "Завантаження...",
|
||||||
|
"theme.IdealImageMessage.offline": "Ваш браузер перебуває в автономному режимі. Зображення не завантажено"
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"theme.PwaReloadPopup.closeButtonAriaLabel": "Закрити",
|
||||||
|
"theme.PwaReloadPopup.info": "Доступна нова версія",
|
||||||
|
"theme.PwaReloadPopup.refreshButtonText": "Оновити"
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
{
|
||||||
|
"theme.AnnouncementBar.closeButtonAriaLabel": "Закрити",
|
||||||
|
"theme.BackToTopButton.buttonAriaLabel": "Прокрутити до початку",
|
||||||
|
"theme.CodeBlock.copied": "Скопійовано",
|
||||||
|
"theme.CodeBlock.copy": "Копіювати",
|
||||||
|
"theme.CodeBlock.copyButtonAriaLabel": "Копіювати в буфер обміну",
|
||||||
|
"theme.CodeBlock.wordWrapToggle": "Перемикання обведення слів",
|
||||||
|
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Згорнути/розгорнути категорію '{label}'",
|
||||||
|
"theme.ErrorPageContent.title": "На сторінці стався збій.",
|
||||||
|
"theme.ErrorPageContent.tryAgain": "Спробуйте ще раз",
|
||||||
|
"theme.NotFound.p1": "На жаль, ми не змогли знайти сторінку, яку ви запитували.",
|
||||||
|
"theme.NotFound.p2": "Будь ласка, зверніться до власника сайту, з якого ви перейшли на це посилання, щоб повідомити, що посилання не працює.",
|
||||||
|
"theme.NotFound.title": "Сторінку не знайдено",
|
||||||
|
"theme.TOCCollapsible.toggleButtonLabel": "Зміст цієї сторінки",
|
||||||
|
"theme.admonition.caution": "обережно",
|
||||||
|
"theme.admonition.danger": "небезпека",
|
||||||
|
"theme.admonition.info": "інформація",
|
||||||
|
"theme.admonition.note": "примітка",
|
||||||
|
"theme.admonition.tip": "порада",
|
||||||
|
"theme.blog.archive.description": "Архів",
|
||||||
|
"theme.blog.archive.title": "Архів",
|
||||||
|
"theme.blog.paginator.navAriaLabel": "Навігація по сторінці списку блогів",
|
||||||
|
"theme.blog.paginator.newerEntries": "Наступні записи",
|
||||||
|
"theme.blog.paginator.olderEntries": "Попередні записи",
|
||||||
|
"theme.blog.post.paginator.navAriaLabel": "Навігація по сторінці посту блогу",
|
||||||
|
"theme.blog.post.paginator.newerPost": "Наступний пост",
|
||||||
|
"theme.blog.post.paginator.olderPost": "Попередній пост",
|
||||||
|
"theme.blog.post.plurals": "{count} запис|{count} записи|{count} записів",
|
||||||
|
"theme.blog.post.readMore": "Читати далі",
|
||||||
|
"theme.blog.post.readMoreLabel": "Докладніше про {title}",
|
||||||
|
"theme.blog.post.readingTime.plurals": "{readingTime} хв. читання",
|
||||||
|
"theme.blog.sidebar.navAriaLabel": "Навігація за останніми постами у блозі",
|
||||||
|
"theme.blog.tagTitle": "{nPosts} з тегом \"{tagName}\"",
|
||||||
|
"theme.colorToggle.ariaLabel": "Перемикання між темним та світлим режимом (зараз використовується {mode})",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.dark": "Темний режим",
|
||||||
|
"theme.colorToggle.ariaLabel.mode.light": "Світлий режим",
|
||||||
|
"theme.common.editThisPage": "Відредагувати цю сторінку",
|
||||||
|
"theme.common.headingLinkTitle": "Пряме посилання на цей заголовок",
|
||||||
|
"theme.common.skipToMainContent": "Перейти до основного вмісту",
|
||||||
|
"theme.docs.DocCard.categoryDescription": "{count} елемент|{count} елементи|{count} елементів",
|
||||||
|
"theme.docs.breadcrumbs.home": "Головна сторінка",
|
||||||
|
"theme.docs.breadcrumbs.navAriaLabel": "Навігаційний ланцюжок поточної сторінки",
|
||||||
|
"theme.docs.paginator.navAriaLabel": "Навігація по сторінці документації",
|
||||||
|
"theme.docs.paginator.next": "Наступна сторінка",
|
||||||
|
"theme.docs.paginator.previous": "Попередня сторінка",
|
||||||
|
"theme.docs.sidebar.collapseButtonAriaLabel": "Згорнути сайдбар",
|
||||||
|
"theme.docs.sidebar.collapseButtonTitle": "Згорнути сайдбар",
|
||||||
|
"theme.docs.sidebar.expandButtonAriaLabel": "Розгорнути сайдбар",
|
||||||
|
"theme.docs.sidebar.expandButtonTitle": "Розгорнути сайдбар",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} з тегом \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "Одна сторінка|{count} сторінки|{count} сторінок",
|
||||||
|
"theme.docs.versionBadge.label": "Версія: {versionLabel}",
|
||||||
|
"theme.docs.versions.latestVersionLinkLabel": "остання версія",
|
||||||
|
"theme.docs.versions.latestVersionSuggestionLabel": "Актуальна документація знаходиться на сторінці {latestVersionLink} ({versionLabel}).",
|
||||||
|
"theme.docs.versions.unmaintainedVersionLabel": "Це документація {siteTitle} для версії {versionLabel}, яка вже не підтримується.",
|
||||||
|
"theme.docs.versions.unreleasedVersionLabel": "Це документація для майбутньої версії {siteTitle} {versionLabel}.",
|
||||||
|
"theme.lastUpdated.atDate": " {date}",
|
||||||
|
"theme.lastUpdated.byUser": " від {user}",
|
||||||
|
"theme.lastUpdated.lastUpdatedAtBy": "Останнє оновлення{atDate}{byUser}",
|
||||||
|
"theme.navbar.mobileLanguageDropdown.label": "Мови",
|
||||||
|
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Перейти до головного меню",
|
||||||
|
"theme.navbar.mobileVersionsDropdown.label": "Версії",
|
||||||
|
"theme.tags.tagsListLabel": "Теги:",
|
||||||
|
"theme.tags.tagsPageLink": "Переглянути всі теги",
|
||||||
|
"theme.tags.tagsPageTitle": "Теги"
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"theme.Playground.liveEditor": "Інтерактивний редактор",
|
||||||
|
"theme.Playground.result": "Результат"
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"theme.SearchBar.label": "Пошук",
|
||||||
|
"theme.SearchBar.seeAll": "Переглянути всі результати ({count})",
|
||||||
|
"theme.SearchModal.errorScreen.helpText": "Перевірте підключення до мережі.",
|
||||||
|
"theme.SearchModal.errorScreen.titleText": "Не вдалося отримати результати",
|
||||||
|
"theme.SearchModal.footer.closeKeyAriaLabel": "Клавіша Escape",
|
||||||
|
"theme.SearchModal.footer.closeText": "закрити",
|
||||||
|
"theme.SearchModal.footer.navigateDownKeyAriaLabel": "Стрілка вниз",
|
||||||
|
"theme.SearchModal.footer.navigateText": "до навігації",
|
||||||
|
"theme.SearchModal.footer.navigateUpKeyAriaLabel": "Стрілка вгору",
|
||||||
|
"theme.SearchModal.footer.searchByText": "Пошук за допомогою",
|
||||||
|
"theme.SearchModal.footer.selectKeyAriaLabel": "Клавіша Enter",
|
||||||
|
"theme.SearchModal.footer.selectText": "обрати",
|
||||||
|
"theme.SearchModal.noResultsScreen.noResultsText": "Немає результатів для",
|
||||||
|
"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": "Дайте нам знати.",
|
||||||
|
"theme.SearchModal.noResultsScreen.reportMissingResultsText": "Чи вважаєте ви, що цей запит має повернути результати?",
|
||||||
|
"theme.SearchModal.noResultsScreen.suggestedQueryText": "Спробуйте пошукати",
|
||||||
|
"theme.SearchModal.placeholder": "Пошук документів",
|
||||||
|
"theme.SearchModal.searchBox.cancelButtonText": "Скасувати",
|
||||||
|
"theme.SearchModal.searchBox.resetButtonTitle": "Очистити запит",
|
||||||
|
"theme.SearchModal.startScreen.favoriteSearchesTitle": "Обране",
|
||||||
|
"theme.SearchModal.startScreen.noRecentSearchesText": "Немає останніх пошуків",
|
||||||
|
"theme.SearchModal.startScreen.recentSearchesTitle": "Останні",
|
||||||
|
"theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": "Видалити цей пошук з обраного",
|
||||||
|
"theme.SearchModal.startScreen.removeRecentSearchButtonTitle": "Видалити цей пошук з історії",
|
||||||
|
"theme.SearchModal.startScreen.saveRecentSearchButtonTitle": "Зберегти цей пошук",
|
||||||
|
"theme.SearchPage.algoliaLabel": "Пошук за допомогою Algolia",
|
||||||
|
"theme.SearchPage.documentsFound.plurals": "{count} документ|{count} документи|{count} документів",
|
||||||
|
"theme.SearchPage.emptyResultsTitle": "Пошук по сайту",
|
||||||
|
"theme.SearchPage.existingResultsTitle": "Результати пошуку за запитом \"{query}\"",
|
||||||
|
"theme.SearchPage.fetchingNewResults": "Завантаження нових результатів пошуку...",
|
||||||
|
"theme.SearchPage.inputLabel": "Пошук",
|
||||||
|
"theme.SearchPage.inputPlaceholder": "Введіть фразу для пошуку",
|
||||||
|
"theme.SearchPage.noResultsText": "За запитом нічого не знайдено"
|
||||||
|
}
|
|
@ -1,29 +1,29 @@
|
||||||
{
|
{
|
||||||
"theme.SearchBar.label": "Tìm kiếm",
|
"theme.SearchBar.label": "Tìm kiếm",
|
||||||
"theme.SearchBar.seeAll": "Xem tất cả {count} kết quả",
|
"theme.SearchBar.seeAll": "Xem tất cả {count} kết quả",
|
||||||
"theme.SearchModal.errorScreen.helpText": "You might want to check your network connection.",
|
"theme.SearchModal.errorScreen.helpText": "Bạn nên kiểm tra lại kết nối mạng của mình.",
|
||||||
"theme.SearchModal.errorScreen.titleText": "Unable to fetch results",
|
"theme.SearchModal.errorScreen.titleText": "Không thể tìm nạp dữ liệu",
|
||||||
"theme.SearchModal.footer.closeKeyAriaLabel": "Escape key",
|
"theme.SearchModal.footer.closeKeyAriaLabel": "Phím thoát",
|
||||||
"theme.SearchModal.footer.closeText": "to close",
|
"theme.SearchModal.footer.closeText": "để đóng",
|
||||||
"theme.SearchModal.footer.navigateDownKeyAriaLabel": "Arrow down",
|
"theme.SearchModal.footer.navigateDownKeyAriaLabel": "Mũi tên xuống",
|
||||||
"theme.SearchModal.footer.navigateText": "to navigate",
|
"theme.SearchModal.footer.navigateText": "để điều hướng",
|
||||||
"theme.SearchModal.footer.navigateUpKeyAriaLabel": "Arrow up",
|
"theme.SearchModal.footer.navigateUpKeyAriaLabel": "Mũi tên lên",
|
||||||
"theme.SearchModal.footer.searchByText": "Search by",
|
"theme.SearchModal.footer.searchByText": "Tìm kiếm theo",
|
||||||
"theme.SearchModal.footer.selectKeyAriaLabel": "Enter key",
|
"theme.SearchModal.footer.selectKeyAriaLabel": "Nhập khóa",
|
||||||
"theme.SearchModal.footer.selectText": "to select",
|
"theme.SearchModal.footer.selectText": "để chọn",
|
||||||
"theme.SearchModal.noResultsScreen.noResultsText": "No results for",
|
"theme.SearchModal.noResultsScreen.noResultsText": "Không có kết quả dành cho",
|
||||||
"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": "Let us know.",
|
"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": "Hãy để chúng tôi biết.",
|
||||||
"theme.SearchModal.noResultsScreen.reportMissingResultsText": "Believe this query should return results?",
|
"theme.SearchModal.noResultsScreen.reportMissingResultsText": "Tin rằng truy vấn này sẽ trả về kết quả?",
|
||||||
"theme.SearchModal.noResultsScreen.suggestedQueryText": "Try searching for",
|
"theme.SearchModal.noResultsScreen.suggestedQueryText": "Thử tìm kiếm",
|
||||||
"theme.SearchModal.placeholder": "Search docs",
|
"theme.SearchModal.placeholder": "Tìm kiếm tài liệu",
|
||||||
"theme.SearchModal.searchBox.cancelButtonText": "Cancel",
|
"theme.SearchModal.searchBox.cancelButtonText": "Hủy bỏ",
|
||||||
"theme.SearchModal.searchBox.resetButtonTitle": "Clear the query",
|
"theme.SearchModal.searchBox.resetButtonTitle": "Xóa truy vấn",
|
||||||
"theme.SearchModal.startScreen.favoriteSearchesTitle": "Favorite",
|
"theme.SearchModal.startScreen.favoriteSearchesTitle": "Yêu thích",
|
||||||
"theme.SearchModal.startScreen.noRecentSearchesText": "No recent searches",
|
"theme.SearchModal.startScreen.noRecentSearchesText": "Không có tìm kiếm nào gần đây",
|
||||||
"theme.SearchModal.startScreen.recentSearchesTitle": "Recent",
|
"theme.SearchModal.startScreen.recentSearchesTitle": "Gần đây",
|
||||||
"theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": "Remove this search from favorites",
|
"theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": "Xóa tìm kiếm này khỏi danh sách yêu thích",
|
||||||
"theme.SearchModal.startScreen.removeRecentSearchButtonTitle": "Remove this search from history",
|
"theme.SearchModal.startScreen.removeRecentSearchButtonTitle": "Xóa tìm kiếm này khỏi lịch sử",
|
||||||
"theme.SearchModal.startScreen.saveRecentSearchButtonTitle": "Save this search",
|
"theme.SearchModal.startScreen.saveRecentSearchButtonTitle": "Lưu tìm kiếm này",
|
||||||
"theme.SearchPage.algoliaLabel": "Tìm kiếm với Algolia",
|
"theme.SearchPage.algoliaLabel": "Tìm kiếm với Algolia",
|
||||||
"theme.SearchPage.documentsFound.plurals": "Tìm thấy một kết quả|Tìm thấy {count} kết quả",
|
"theme.SearchPage.documentsFound.plurals": "Tìm thấy một kết quả|Tìm thấy {count} kết quả",
|
||||||
"theme.SearchPage.emptyResultsTitle": "Tìm kiếm",
|
"theme.SearchPage.emptyResultsTitle": "Tìm kiếm",
|
||||||
|
|
5
packages/docusaurus-types/src/i18n.d.ts
vendored
5
packages/docusaurus-types/src/i18n.d.ts
vendored
|
@ -11,8 +11,9 @@ export type I18nLocaleConfig = {
|
||||||
/** The label displayed for this locale in the locales dropdown. */
|
/** The label displayed for this locale in the locales dropdown. */
|
||||||
label: string;
|
label: string;
|
||||||
/**
|
/**
|
||||||
* BCP 47 language tag to use in `<html lang="...">` and in
|
* BCP 47 language tag to use in:
|
||||||
* `<link ... hreflang="...">`
|
* - `<html lang="...">` (or any other DOM tag name)
|
||||||
|
* - `<link ... hreflang="...">`
|
||||||
*/
|
*/
|
||||||
htmlLang: string;
|
htmlLang: string;
|
||||||
/** Used to select the locale's CSS and html meta attribute. */
|
/** Used to select the locale's CSS and html meta attribute. */
|
||||||
|
|
|
@ -86,7 +86,7 @@ export function getFileLoaderUtils(): FileLoaderUtils {
|
||||||
*/
|
*/
|
||||||
images: () => ({
|
images: () => ({
|
||||||
use: [loaders.url({folder: 'images'})],
|
use: [loaders.url({folder: 'images'})],
|
||||||
test: /\.(?:ico|jpe?g|png|gif|webp)(?:\?.*)?$/i,
|
test: /\.(?:ico|jpe?g|png|gif|webp|avif)(?:\?.*)?$/i,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
fonts: () => ({
|
fonts: () => ({
|
||||||
|
@ -100,7 +100,7 @@ export function getFileLoaderUtils(): FileLoaderUtils {
|
||||||
*/
|
*/
|
||||||
media: () => ({
|
media: () => ({
|
||||||
use: [loaders.url({folder: 'medias'})],
|
use: [loaders.url({folder: 'medias'})],
|
||||||
test: /\.(?:mp4|webm|ogv|wav|mp3|m4a|aac|oga|flac)$/i,
|
test: /\.(?:mp4|avi|mov|mkv|mpg|mpeg|vob|wmv|m4v|webm|ogv|wav|mp3|m4a|aac|oga|flac)$/i,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
svg: () => ({
|
svg: () => ({
|
||||||
|
|
|
@ -12,7 +12,7 @@ import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
|
||||||
export default function SiteMetadataDefaults(): JSX.Element {
|
export default function SiteMetadataDefaults(): JSX.Element {
|
||||||
const {
|
const {
|
||||||
siteConfig: {favicon, title},
|
siteConfig: {favicon, title, noIndex},
|
||||||
i18n: {currentLocale, localeConfigs},
|
i18n: {currentLocale, localeConfigs},
|
||||||
} = useDocusaurusContext();
|
} = useDocusaurusContext();
|
||||||
const faviconUrl = useBaseUrl(favicon);
|
const faviconUrl = useBaseUrl(favicon);
|
||||||
|
@ -20,9 +20,17 @@ export default function SiteMetadataDefaults(): JSX.Element {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Head>
|
<Head>
|
||||||
|
{/*
|
||||||
|
charSet + generator are handled in the html templates
|
||||||
|
See https://github.com/facebook/docusaurus/pull/7952
|
||||||
|
<meta charSet="UTF-8" />
|
||||||
|
<meta name="generator" content={`Docusaurus v${docusaurusVersion}`} />
|
||||||
|
*/}
|
||||||
<html lang={htmlLang} dir={htmlDir} />
|
<html lang={htmlLang} dir={htmlDir} />
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
<meta property="og:title" content={title} />
|
<meta property="og:title" content={title} />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
{noIndex && <meta name="robots" content="noindex, nofollow" />}
|
||||||
{favicon && <link rel="icon" href={faviconUrl} />}
|
{favicon && <link rel="icon" href={faviconUrl} />}
|
||||||
</Head>
|
</Head>
|
||||||
);
|
);
|
||||||
|
|
|
@ -17,7 +17,9 @@ import {matchRoutes} from 'react-router-config';
|
||||||
* @returns Promise object represents whether pathname has been preloaded
|
* @returns Promise object represents whether pathname has been preloaded
|
||||||
*/
|
*/
|
||||||
export default function preload(pathname: string): Promise<void[]> {
|
export default function preload(pathname: string): Promise<void[]> {
|
||||||
const matches = matchRoutes(routes, pathname);
|
const matches = Array.from(new Set([pathname, decodeURI(pathname)]))
|
||||||
|
.map((p) => matchRoutes(routes, p))
|
||||||
|
.flat();
|
||||||
|
|
||||||
return Promise.all(matches.map((match) => match.route.component.preload?.()));
|
return Promise.all(matches.map((match) => match.route.component.preload?.()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,14 @@ export type WriteTranslationsCLIOptions = Pick<
|
||||||
> &
|
> &
|
||||||
WriteTranslationsOptions;
|
WriteTranslationsOptions;
|
||||||
|
|
||||||
|
function resolveThemeCommonLibDir(): string | undefined {
|
||||||
|
try {
|
||||||
|
return path.dirname(require.resolve('@docusaurus/theme-common'));
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a hack, so that @docusaurus/theme-common translations are extracted!
|
* This is a hack, so that @docusaurus/theme-common translations are extracted!
|
||||||
* A theme doesn't have a way to express that one of its dependency (like
|
* A theme doesn't have a way to express that one of its dependency (like
|
||||||
|
@ -37,14 +45,11 @@ export type WriteTranslationsCLIOptions = Pick<
|
||||||
* We just make an exception and assume that user is using an official theme
|
* We just make an exception and assume that user is using an official theme
|
||||||
*/
|
*/
|
||||||
async function getExtraSourceCodeFilePaths(): Promise<string[]> {
|
async function getExtraSourceCodeFilePaths(): Promise<string[]> {
|
||||||
try {
|
const themeCommonLibDir = resolveThemeCommonLibDir();
|
||||||
const themeCommonSourceDir = path.dirname(
|
if (!themeCommonLibDir) {
|
||||||
require.resolve('@docusaurus/theme-common/lib'),
|
|
||||||
);
|
|
||||||
return globSourceCodeFilePaths([themeCommonSourceDir]);
|
|
||||||
} catch {
|
|
||||||
return []; // User may not use a Docusaurus official theme? Quite unlikely...
|
return []; // User may not use a Docusaurus official theme? Quite unlikely...
|
||||||
}
|
}
|
||||||
|
return globSourceCodeFilePaths([themeCommonLibDir]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function writePluginTranslationFiles({
|
async function writePluginTranslationFiles({
|
||||||
|
@ -108,6 +113,7 @@ Available locales are: ${context.i18n.locales.join(',')}.`,
|
||||||
babelOptions,
|
babelOptions,
|
||||||
await getExtraSourceCodeFilePaths(),
|
await getExtraSourceCodeFilePaths(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const defaultCodeMessages = await getPluginsDefaultCodeTranslationMessages(
|
const defaultCodeMessages = await getPluginsDefaultCodeTranslationMessages(
|
||||||
plugins,
|
plugins,
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta name="generator" content="Docusaurus">
|
<meta name="generator" content="Docusaurus">
|
||||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
<%= htmlWebpackPlugin.options.headTags %>
|
<%= htmlWebpackPlugin.options.headTags %>
|
||||||
|
|
|
@ -10,15 +10,11 @@ export default `
|
||||||
<html <%~ it.htmlAttributes %>>
|
<html <%~ it.htmlAttributes %>>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta name="generator" content="Docusaurus v<%= it.version %>">
|
<meta name="generator" content="Docusaurus v<%= it.version %>">
|
||||||
<% if (it.noIndex) { %>
|
|
||||||
<meta name="robots" content="noindex, nofollow" />
|
|
||||||
<% } %>
|
|
||||||
<%~ it.headTags %>
|
|
||||||
<% it.metaAttributes.forEach((metaAttribute) => { %>
|
<% it.metaAttributes.forEach((metaAttribute) => { %>
|
||||||
<%~ metaAttribute %>
|
<%~ metaAttribute %>
|
||||||
<% }); %>
|
<% }); %>
|
||||||
|
<%~ it.headTags %>
|
||||||
<% it.stylesheets.forEach((stylesheet) => { %>
|
<% it.stylesheets.forEach((stylesheet) => { %>
|
||||||
<link rel="stylesheet" href="<%= it.baseUrl %><%= stylesheet %>" />
|
<link rel="stylesheet" href="<%= it.baseUrl %><%= stylesheet %>" />
|
||||||
<% }); %>
|
<% }); %>
|
||||||
|
|
|
@ -249,3 +249,21 @@ echo "short_initially_hidden_string"
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
[// spell-checker:enable]: #
|
[// spell-checker:enable]: #
|
||||||
|
|
||||||
|
```jsx showLineNumbers
|
||||||
|
import React from 'react';
|
||||||
|
import Layout from '@theme/Layout';
|
||||||
|
|
||||||
|
export default function MyReactPage() {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<h1>My React page</h1>
|
||||||
|
<p>
|
||||||
|
This is a React page. Let's make this sentence bit long. Some more words
|
||||||
|
to make sure... Some more words to make sure... Some more words to make
|
||||||
|
sure...
|
||||||
|
</p>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
17
website/_dogfooding/_pages tests/head-metadata.md
Normal file
17
website/_dogfooding/_pages tests/head-metadata.md
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
## Head Metadata tests
|
||||||
|
|
||||||
|
This page declares the following custom head metadata:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<head>
|
||||||
|
<meta name="generator" value="custom generator name!" />
|
||||||
|
<meta name="viewport" content="initial-scale=1, viewport-fit=cover" />
|
||||||
|
<meta name="robots" content="noindex, nofollow, my-extra-directive" />
|
||||||
|
</head>
|
||||||
|
```
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta name="generator" value="custom generator name!" />
|
||||||
|
<meta name="viewport" content="initial-scale=1, viewport-fit=cover" />
|
||||||
|
<meta name="robots" content="noindex, nofollow, my-extra-directive" />
|
||||||
|
</head>
|
|
@ -29,3 +29,4 @@ import Readme from "../README.md"
|
||||||
- [TOC tests](/tests/pages/page-toc-tests)
|
- [TOC tests](/tests/pages/page-toc-tests)
|
||||||
- [Tabs tests](/tests/pages/tabs-tests)
|
- [Tabs tests](/tests/pages/tabs-tests)
|
||||||
- [z-index tests](/tests/pages/z-index-tests)
|
- [z-index tests](/tests/pages/z-index-tests)
|
||||||
|
- [Head metadata tests](/tests/pages/head-metadata)
|
||||||
|
|
|
@ -71,10 +71,27 @@ const sidebars = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'link',
|
type: 'category',
|
||||||
label: 'External link',
|
label: 'Link tests',
|
||||||
href: 'https://github.com/facebook/docusaurus',
|
|
||||||
className: 'red',
|
className: 'red',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'link',
|
||||||
|
label: 'External link absolute',
|
||||||
|
href: 'https://github.com/facebook/docusaurus',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'link',
|
||||||
|
label: 'pathname:/// link',
|
||||||
|
href: 'pathname:///some/local/path',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'link',
|
||||||
|
label: 'pathname:/// link (no baseUrl)',
|
||||||
|
href: 'pathname:///some/local/path',
|
||||||
|
autoAddBaseUrl: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'category',
|
type: 'category',
|
||||||
|
|
|
@ -26,6 +26,11 @@ const dogfoodingPluginInstances = [
|
||||||
id: 'docs-tests',
|
id: 'docs-tests',
|
||||||
routeBasePath: '/tests/docs',
|
routeBasePath: '/tests/docs',
|
||||||
sidebarPath: '_dogfooding/docs-tests-sidebars.js',
|
sidebarPath: '_dogfooding/docs-tests-sidebars.js',
|
||||||
|
versions: {
|
||||||
|
current: {
|
||||||
|
noIndex: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
// Using a _ prefix to test against an edge case regarding MDX partials: https://github.com/facebook/docusaurus/discussions/5181#discussioncomment-1018079
|
// Using a _ prefix to test against an edge case regarding MDX partials: https://github.com/facebook/docusaurus/discussions/5181#discussioncomment-1018079
|
||||||
path: '_dogfooding/_docs tests',
|
path: '_dogfooding/_docs tests',
|
||||||
|
|
|
@ -4,9 +4,8 @@ This section is not going to be very structured, but we will cover the following
|
||||||
|
|
||||||
```mdx-code-block
|
```mdx-code-block
|
||||||
import DocCardList from '@theme/DocCardList';
|
import DocCardList from '@theme/DocCardList';
|
||||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
||||||
|
|
||||||
<DocCardList items={useCurrentSidebarCategory().items}/>
|
<DocCardList />
|
||||||
```
|
```
|
||||||
|
|
||||||
We will assume that you have finished the guides, and know the basics like how to configure plugins, how to write React components, etc. These sections will have plugin authors and code contributors in mind, so we may occasionally refer to [plugin APIs](../api/plugin-methods/README.md) or other architecture details. Don't panic if you don't understand everything😉
|
We will assume that you have finished the guides, and know the basics like how to configure plugins, how to write React components, etc. These sections will have plugin authors and code contributors in mind, so we may occasionally refer to [plugin APIs](../api/plugin-methods/README.md) or other architecture details. Don't panic if you don't understand everything😉
|
||||||
|
|
|
@ -157,7 +157,7 @@ module.exports = {
|
||||||
- `localeConfigs`: Individual options for each locale.
|
- `localeConfigs`: Individual options for each locale.
|
||||||
- `label`: The label displayed for this locale in the locales dropdown.
|
- `label`: The label displayed for this locale in the locales dropdown.
|
||||||
- `direction`: `ltr` (default) or `rtl` (for [right-to-left languages](https://developer.mozilla.org/en-US/docs/Glossary/rtl) like Farsi, Arabic, Hebrew, etc.). Used to select the locale's CSS and HTML meta attribute.
|
- `direction`: `ltr` (default) or `rtl` (for [right-to-left languages](https://developer.mozilla.org/en-US/docs/Glossary/rtl) like Farsi, Arabic, Hebrew, etc.). Used to select the locale's CSS and HTML meta attribute.
|
||||||
- `htmlLang`: BCP 47 language tag to use in `<html lang="...">` and in `<link ... hreflang="...">`
|
- `htmlLang`: BCP 47 language tag to use in `<html lang="...">` (or any other DOM tag name) and in `<link ... hreflang="...">`
|
||||||
- `calendar`: the [calendar](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar) used to calculate the date era. Note that it doesn't control the actual string displayed: `MM/DD/YYYY` and `DD/MM/YYYY` are both `gregory`. To choose the format (`DD/MM/YYYY` or `MM/DD/YYYY`), set your locale name to `en-GB` or `en-US` (`en` means `en-US`).
|
- `calendar`: the [calendar](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar) used to calculate the date era. Note that it doesn't control the actual string displayed: `MM/DD/YYYY` and `DD/MM/YYYY` are both `gregory`. To choose the format (`DD/MM/YYYY` or `MM/DD/YYYY`), set your locale name to `en-GB` or `en-US` (`en` means `en-US`).
|
||||||
- `path`: Root folder that all plugin localization folders of this locale are relative to. Will be resolved against `i18n.path`. Defaults to the locale's name. Note: this has no effect on the locale's `baseUrl`—customization of base URL is a work-in-progress.
|
- `path`: Root folder that all plugin localization folders of this locale are relative to. Will be resolved against `i18n.path`. Defaults to the locale's name. Note: this has no effect on the locale's `baseUrl`—customization of base URL is a work-in-progress.
|
||||||
|
|
||||||
|
@ -509,15 +509,11 @@ module.exports = {
|
||||||
<html <%~ it.htmlAttributes %>>
|
<html <%~ it.htmlAttributes %>>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta name="generator" content="Docusaurus v<%= it.version %>">
|
<meta name="generator" content="Docusaurus v<%= it.version %>">
|
||||||
<% if (it.noIndex) { %>
|
|
||||||
<meta name="robots" content="noindex, nofollow" />
|
|
||||||
<% } %>
|
|
||||||
<%~ it.headTags %>
|
|
||||||
<% it.metaAttributes.forEach((metaAttribute) => { %>
|
<% it.metaAttributes.forEach((metaAttribute) => { %>
|
||||||
<%~ metaAttribute %>
|
<%~ metaAttribute %>
|
||||||
<% }); %>
|
<% }); %>
|
||||||
|
<%~ it.headTags %>
|
||||||
<% it.stylesheets.forEach((stylesheet) => { %>
|
<% it.stylesheets.forEach((stylesheet) => { %>
|
||||||
<link rel="stylesheet" href="<%= it.baseUrl %><%= stylesheet %>" />
|
<link rel="stylesheet" href="<%= it.baseUrl %><%= stylesheet %>" />
|
||||||
<% }); %>
|
<% }); %>
|
||||||
|
|
|
@ -142,23 +142,25 @@ type CategoryIndexMatcher = (param: {
|
||||||
#### `VersionsConfig` {#VersionsConfig}
|
#### `VersionsConfig` {#VersionsConfig}
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
type VersionsConfig = {
|
type VersionConfig = {
|
||||||
[versionName: string]: {
|
/**
|
||||||
/**
|
* The base path of the version, will be appended to `baseUrl` +
|
||||||
* The base path of the version, will be appended to `baseUrl` +
|
* `routeBasePath`.
|
||||||
* `routeBasePath`.
|
*/
|
||||||
*/
|
path?: string;
|
||||||
path?: string;
|
/** The label of the version to be used in badges, dropdowns, etc. */
|
||||||
/** The label of the version to be used in badges, dropdowns, etc. */
|
label?: string;
|
||||||
label?: string;
|
/** The banner to show at the top of a doc of that version. */
|
||||||
/** The banner to show at the top of a doc of that version. */
|
banner?: 'none' | 'unreleased' | 'unmaintained';
|
||||||
banner?: 'none' | 'unreleased' | 'unmaintained';
|
/** Show a badge with the version label at the top of each doc. */
|
||||||
/** Show a badge with the version label at the top of each doc. */
|
badge?: boolean;
|
||||||
badge?: boolean;
|
/** Prevents search engines from indexing this version */
|
||||||
/** Add a custom class name to the <html> element of each doc */
|
noIndex?: boolean;
|
||||||
className?: string;
|
/** Add a custom class name to the <html> element of each doc */
|
||||||
};
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type VersionsConfig = {[versionName: string]: VersionConfig};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example configuration {#ex-config}
|
### Example configuration {#ex-config}
|
||||||
|
|
|
@ -35,9 +35,8 @@ This section serves as an overview of miscellaneous features of the doc sidebar.
|
||||||
|
|
||||||
```mdx-code-block
|
```mdx-code-block
|
||||||
import DocCardList from '@theme/DocCardList';
|
import DocCardList from '@theme/DocCardList';
|
||||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
||||||
|
|
||||||
<DocCardList items={useCurrentSidebarCategory().items}/>
|
<DocCardList />
|
||||||
```
|
```
|
||||||
|
|
||||||
## Default sidebar {#default-sidebar}
|
## Default sidebar {#default-sidebar}
|
||||||
|
|
|
@ -8,6 +8,7 @@ slug: /sidebar/items
|
||||||
```mdx-code-block
|
```mdx-code-block
|
||||||
import Tabs from '@theme/Tabs';
|
import Tabs from '@theme/Tabs';
|
||||||
import TabItem from '@theme/TabItem';
|
import TabItem from '@theme/TabItem';
|
||||||
|
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||||
```
|
```
|
||||||
|
|
||||||
We have introduced three types of item types in the example in the previous section: `doc`, `category`, and `link`, whose usages are fairly intuitive. We will formally introduce their APIs. There's also a fourth type: `autogenerated`, which we will explain in detail later.
|
We have introduced three types of item types in the example in the previous section: `doc`, `category`, and `link`, whose usages are fairly intuitive. We will formally introduce their APIs. There's also a fourth type: `autogenerated`, which we will explain in detail later.
|
||||||
|
@ -291,18 +292,23 @@ See it in action on the [i18n introduction page](../../../i18n/i18n-introduction
|
||||||
|
|
||||||
#### Embedding generated index in doc page {#embedding-generated-index-in-doc-page}
|
#### Embedding generated index in doc page {#embedding-generated-index-in-doc-page}
|
||||||
|
|
||||||
You can embed the generated cards list in a normal doc page as well, as long as the doc is used as a category index page. To do so, you need to use the `DocCardList` component, paired with the `useCurrentSidebarCategory` hook.
|
You can embed the generated cards list in a normal doc page as well with the `DocCardList` component. It will display all the sidebar items of the parent category of the current document.
|
||||||
|
|
||||||
```jsx title="a-category-index-page.md"
|
```md title="docs/sidebar/index.md"
|
||||||
import DocCardList from '@theme/DocCardList';
|
import DocCardList from '@theme/DocCardList';
|
||||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
||||||
|
|
||||||
In this section, we will introduce the following concepts:
|
<DocCardList />
|
||||||
|
|
||||||
<DocCardList items={useCurrentSidebarCategory().items}/>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
See this in action on the [sidebar guides page](index.md).
|
```mdx-code-block
|
||||||
|
<BrowserWindow>
|
||||||
|
|
||||||
|
import DocCardList from '@theme/DocCardList';
|
||||||
|
|
||||||
|
<DocCardList />
|
||||||
|
|
||||||
|
</BrowserWindow>
|
||||||
|
```
|
||||||
|
|
||||||
### Collapsible categories {#collapsible-categories}
|
### Collapsible categories {#collapsible-categories}
|
||||||
|
|
||||||
|
|
|
@ -65,11 +65,9 @@ import LiteYouTubeEmbed from 'react-lite-youtube-embed';
|
||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Disclaimer {#disclaimer}
|
## Migrating from v1 {#migrating-from-v1}
|
||||||
|
|
||||||
Docusaurus v2 is **beta** but already quite stable and widely used.
|
Docusaurus v2 has been a total rewrite from Docusaurus v1, taking advantage of a completely modernized toolchain. After [v2's official release](https://docusaurus.io/blog/2022/08/01/announcing-docusaurus-2.0), we highly encourage you to **use Docusaurus v2 over Docusaurus v1**, as Docusaurus v1 has been deprecated.
|
||||||
|
|
||||||
We highly encourage you to **use Docusaurus v2 over Docusaurus v1**, as Docusaurus v1 will be deprecated soon.
|
|
||||||
|
|
||||||
A [lot of users](/showcase) are already using Docusaurus v2 ([trends](https://www.npmtrends.com/docusaurus-vs-@docusaurus/core)).
|
A [lot of users](/showcase) are already using Docusaurus v2 ([trends](https://www.npmtrends.com/docusaurus-vs-@docusaurus/core)).
|
||||||
|
|
||||||
|
@ -83,7 +81,9 @@ A [lot of users](/showcase) are already using Docusaurus v2 ([trends](https://ww
|
||||||
**Use [Docusaurus v1](https://v1.docusaurus.io/) if:**
|
**Use [Docusaurus v1](https://v1.docusaurus.io/) if:**
|
||||||
|
|
||||||
- :x: You don't want a single-page application (SPA)
|
- :x: You don't want a single-page application (SPA)
|
||||||
- :x: You need support for IE11
|
- :x: You need support for IE11 (...do you? IE [has already reached end-of-life](https://docs.microsoft.com/en-us/lifecycle/products/internet-explorer-11) and is no longer officially supported)
|
||||||
|
|
||||||
|
For existing v1 users that are seeking to upgrade to v2, you can follow our [migration guide](./migration/migration-overview.md).
|
||||||
|
|
||||||
## Features {#features}
|
## Features {#features}
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,11 @@ Read more about the robots file in [the Google documentation](https://developers
|
||||||
|
|
||||||
:::caution
|
:::caution
|
||||||
|
|
||||||
**Important**: the `robots.txt` file does **not** prevent HTML pages from being indexed. Use `<meta name="robots" content="noindex">` as [page metadata](#single-page-metadata) to prevent it from appearing in search results entirely.
|
**Important**: the `robots.txt` file does **not** prevent HTML pages from being indexed.
|
||||||
|
|
||||||
|
To prevent your whole Docusaurus site from being indexed, use the [`noIndex`](./api/docusaurus.config.js.md#noIndex) site config. Some [hosting providers](./deployment.mdx) may also let you configure a `X-Robots-Tag: noindex` HTTP header (GitHub Pages does not support this).
|
||||||
|
|
||||||
|
To prevent a single page from being indexed, use `<meta name="robots" content="noindex">` as [page metadata](#single-page-metadata). Read more about the [robots meta tag](https://developers.google.com/search/docs/advanced/robots/robots_meta_tag).
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
@ -132,6 +136,20 @@ Read more about the robots file in [the Google documentation](https://developers
|
||||||
|
|
||||||
Docusaurus provides the [`@docusaurus/plugin-sitemap`](./api/plugins/plugin-sitemap.md) plugin, which is shipped with `preset-classic` by default. It autogenerates a `sitemap.xml` file which will be available at `https://example.com/[baseUrl]/sitemap.xml` after the production build. This sitemap metadata helps search engine crawlers crawl your site more accurately.
|
Docusaurus provides the [`@docusaurus/plugin-sitemap`](./api/plugins/plugin-sitemap.md) plugin, which is shipped with `preset-classic` by default. It autogenerates a `sitemap.xml` file which will be available at `https://example.com/[baseUrl]/sitemap.xml` after the production build. This sitemap metadata helps search engine crawlers crawl your site more accurately.
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
|
||||||
|
The sitemap plugin automatically filters pages containing a `noindex` [robots meta directive](https://developers.google.com/search/docs/advanced/robots/robots_meta_tag).
|
||||||
|
|
||||||
|
For example, [`/examples/noIndex`](/examples/noIndex) is not included in the [Docusaurus sitemap.xml file](pathname:///sitemap.xml) because it contains the following [page metadata](#single-page-metadata):
|
||||||
|
|
||||||
|
```html
|
||||||
|
<head>
|
||||||
|
<meta name="robots" content="noindex, nofollow" />
|
||||||
|
</head>
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
## Human readable links {#human-readable-links}
|
## Human readable links {#human-readable-links}
|
||||||
|
|
||||||
Docusaurus uses your file names as links, but you can always change that using slugs, see this [tutorial](./guides/docs/docs-introduction.md#document-id) for more details.
|
Docusaurus uses your file names as links, but you can always change that using slugs, see this [tutorial](./guides/docs/docs-introduction.md#document-id) for more details.
|
||||||
|
|
|
@ -356,7 +356,8 @@ const config = {
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
sitemap: {
|
sitemap: {
|
||||||
ignorePatterns: ['/tests/**'],
|
// Note: /tests/docs already has noIndex: true
|
||||||
|
ignorePatterns: ['/tests/{blog,pages}/**'],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|
25
website/src/pages/examples/noIndex.md
Normal file
25
website/src/pages/examples/noIndex.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# No Index Page example
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta name="robots" content="nOiNdeX, NoFolLoW" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
This page will not be indexed by search engines because it contains the page following [page metadata](/docs/seo#single-page-metadata) markup:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<head>
|
||||||
|
<meta name="robots" content="noindex, nofollow" />
|
||||||
|
</head>
|
||||||
|
```
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
|
||||||
|
The sitemap plugin filters pages containing a `noindex` content value. This page doesn't appear in Docusaurus [sitemap.xml](pathname:///sitemap.xml) file.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
:::note
|
||||||
|
|
||||||
|
Robots directives are [case-insensitive](https://developers.google.com/search/docs/advanced/robots/robots_meta_tag#directives).
|
||||||
|
|
||||||
|
:::
|
|
@ -65,11 +65,9 @@ import LiteYouTubeEmbed from 'react-lite-youtube-embed';
|
||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Disclaimer {#disclaimer}
|
## Migrating from v1 {#migrating-from-v1}
|
||||||
|
|
||||||
Docusaurus v2 is **beta** but already quite stable and widely used.
|
Docusaurus v2 has been a total rewrite from Docusaurus v1, taking advantage of a completely modernized toolchain. After [v2's official release](https://docusaurus.io/blog/2022/08/01/announcing-docusaurus-2.0), we highly encourage you to **use Docusaurus v2 over Docusaurus v1**, as Docusaurus v1 has been deprecated.
|
||||||
|
|
||||||
We highly encourage you to **use Docusaurus v2 over Docusaurus v1**, as Docusaurus v1 will be deprecated soon.
|
|
||||||
|
|
||||||
A [lot of users](/showcase) are already using Docusaurus v2 ([trends](https://www.npmtrends.com/docusaurus-vs-@docusaurus/core)).
|
A [lot of users](/showcase) are already using Docusaurus v2 ([trends](https://www.npmtrends.com/docusaurus-vs-@docusaurus/core)).
|
||||||
|
|
||||||
|
@ -83,7 +81,9 @@ A [lot of users](/showcase) are already using Docusaurus v2 ([trends](https://ww
|
||||||
**Use [Docusaurus v1](https://v1.docusaurus.io/) if:**
|
**Use [Docusaurus v1](https://v1.docusaurus.io/) if:**
|
||||||
|
|
||||||
- :x: You don't want a single-page application (SPA)
|
- :x: You don't want a single-page application (SPA)
|
||||||
- :x: You need support for IE11
|
- :x: You need support for IE11 (...do you? IE [has already reached end-of-life](https://docs.microsoft.com/en-us/lifecycle/products/internet-explorer-11) and is no longer officially supported)
|
||||||
|
|
||||||
|
For existing v1 users that are seeking to upgrade to v2, you can follow our [migration guide](./migration/migration-overview.md).
|
||||||
|
|
||||||
## Features {#features}
|
## Features {#features}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue