mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-17 19:16:58 +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
|
||||
/*
|
||||
tutorialSidebar: [
|
||||
'intro',
|
||||
'hello',
|
||||
{
|
||||
type: 'category',
|
||||
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?
|
||||
|
||||
- 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 [search bar](https://docusaurus.io/docs/search)
|
||||
- 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"
|
||||
module.exports = {
|
||||
tutorialSidebar: [
|
||||
'intro',
|
||||
// highlight-next-line
|
||||
'hello',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Tutorial',
|
||||
// highlight-next-line
|
||||
items: ['hello'],
|
||||
items: ['tutorial-basics/create-a-document'],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -19,10 +19,12 @@ const sidebars = {
|
|||
// But you can create a sidebar manually
|
||||
/*
|
||||
tutorialSidebar: [
|
||||
'intro',
|
||||
'hello',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Tutorial',
|
||||
items: ['hello'],
|
||||
items: ['tutorial-basics/create-a-document'],
|
||||
},
|
||||
],
|
||||
*/
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
"webpack": "^5.73.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.21",
|
||||
"escape-string-regexp": "^4.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
"webpack": "^5.73.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.21",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/picomatch": "^2.3.0",
|
||||
"commander": "^5.1.0",
|
||||
|
|
|
@ -901,6 +901,7 @@ exports[`simple website content: data 1`] = `
|
|||
"label": "Next",
|
||||
"banner": null,
|
||||
"badge": false,
|
||||
"noIndex": false,
|
||||
"className": "docs-version-current",
|
||||
"isLast": true,
|
||||
"docsSidebars": {
|
||||
|
@ -2608,6 +2609,7 @@ exports[`versioned website (community) content: data 1`] = `
|
|||
"label": "1.0.0",
|
||||
"banner": null,
|
||||
"badge": true,
|
||||
"noIndex": false,
|
||||
"className": "docs-version-1.0.0",
|
||||
"isLast": true,
|
||||
"docsSidebars": {
|
||||
|
@ -2635,6 +2637,7 @@ exports[`versioned website (community) content: data 1`] = `
|
|||
"label": "Next",
|
||||
"banner": "unreleased",
|
||||
"badge": true,
|
||||
"noIndex": false,
|
||||
"className": "docs-version-current",
|
||||
"isLast": false,
|
||||
"docsSidebars": {
|
||||
|
@ -3477,6 +3480,7 @@ exports[`versioned website content: data 1`] = `
|
|||
"label": "1.0.0",
|
||||
"banner": "unmaintained",
|
||||
"badge": true,
|
||||
"noIndex": false,
|
||||
"className": "docs-version-1.0.0",
|
||||
"isLast": false,
|
||||
"docsSidebars": {
|
||||
|
@ -3544,6 +3548,7 @@ exports[`versioned website content: data 1`] = `
|
|||
"label": "1.0.1",
|
||||
"banner": null,
|
||||
"badge": true,
|
||||
"noIndex": true,
|
||||
"className": "docs-version-1.0.1",
|
||||
"isLast": true,
|
||||
"docsSidebars": {
|
||||
|
@ -3599,6 +3604,7 @@ exports[`versioned website content: data 1`] = `
|
|||
"label": "Next",
|
||||
"banner": "unreleased",
|
||||
"badge": true,
|
||||
"noIndex": false,
|
||||
"className": "docs-version-current",
|
||||
"isLast": false,
|
||||
"docsSidebars": {
|
||||
|
@ -3674,6 +3680,7 @@ exports[`versioned website content: data 1`] = `
|
|||
"label": "withSlugs",
|
||||
"banner": "unmaintained",
|
||||
"badge": true,
|
||||
"noIndex": false,
|
||||
"className": "docs-version-withSlugs",
|
||||
"isLast": false,
|
||||
"docsSidebars": {
|
||||
|
|
|
@ -362,6 +362,11 @@ describe('versioned website', () => {
|
|||
options: {
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
versions: {
|
||||
'1.0.1': {
|
||||
noIndex: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const plugin = await pluginContentDocs(context, options);
|
||||
|
|
|
@ -76,6 +76,7 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
version1: {
|
||||
path: 'hello',
|
||||
label: 'world',
|
||||
noIndex: true,
|
||||
},
|
||||
},
|
||||
sidebarCollapsible: false,
|
||||
|
|
|
@ -59,6 +59,7 @@ const VersionOptionsSchema = Joi.object({
|
|||
banner: Joi.string().equal('none', 'unreleased', 'unmaintained').optional(),
|
||||
badge: Joi.boolean().optional(),
|
||||
className: Joi.string().optional(),
|
||||
noIndex: Joi.boolean().optional(),
|
||||
});
|
||||
|
||||
const VersionsOptionsSchema = Joi.object()
|
||||
|
|
|
@ -125,6 +125,25 @@ declare module '@docusaurus/plugin-content-docs' {
|
|||
// TODO support custom version banner?
|
||||
// {type: "error", content: "html content"}
|
||||
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 = {
|
||||
/**
|
||||
* 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. */
|
||||
includeCurrentVersion: boolean;
|
||||
/** Independent customization of each version's properties. */
|
||||
versions: {
|
||||
[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;
|
||||
};
|
||||
};
|
||||
versions: {[versionName: string]: VersionOptions};
|
||||
};
|
||||
export type SidebarOptions = {
|
||||
/**
|
||||
|
@ -263,6 +266,8 @@ declare module '@docusaurus/plugin-content-docs' {
|
|||
banner: VersionBanner | null;
|
||||
/** 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;
|
||||
/**
|
||||
|
@ -500,7 +505,7 @@ declare module '@docusaurus/plugin-content-docs' {
|
|||
|
||||
export type PropVersionMetadata = Pick<
|
||||
VersionMetadata,
|
||||
'label' | 'banner' | 'badge' | 'className' | 'isLast'
|
||||
'label' | 'banner' | 'badge' | 'className' | 'isLast' | 'noIndex'
|
||||
> & {
|
||||
/** ID of the docs plugin this version belongs to. */
|
||||
pluginId: string;
|
||||
|
|
|
@ -142,6 +142,7 @@ export function toVersionMetadataProp(
|
|||
label: loadedVersion.label,
|
||||
banner: loadedVersion.banner,
|
||||
badge: loadedVersion.badge,
|
||||
noIndex: loadedVersion.noIndex,
|
||||
className: loadedVersion.className,
|
||||
isLast: loadedVersion.isLast,
|
||||
docsSidebars: toSidebarsProp(loadedVersion),
|
||||
|
|
|
@ -44,6 +44,7 @@ export type SidebarItemLink = SidebarItemBase & {
|
|||
type: 'link';
|
||||
href: string;
|
||||
label: string;
|
||||
autoAddBaseUrl?: boolean;
|
||||
};
|
||||
|
||||
export type SidebarItemAutogenerated = SidebarItemBase & {
|
||||
|
|
|
@ -59,6 +59,7 @@ const sidebarItemHtmlSchema = sidebarItemBaseSchema.append<SidebarItemHtml>({
|
|||
const sidebarItemLinkSchema = sidebarItemBaseSchema.append<SidebarItemLink>({
|
||||
type: 'link',
|
||||
href: URISchema.required(),
|
||||
autoAddBaseUrl: Joi.boolean(),
|
||||
label: Joi.string()
|
||||
.required()
|
||||
.messages({'any.unknown': '"label" must be a string'}),
|
||||
|
|
|
@ -56,6 +56,7 @@ describe('readVersionsMetadata', () => {
|
|||
path: '/docs',
|
||||
banner: null,
|
||||
badge: false,
|
||||
noIndex: false,
|
||||
className: 'docs-version-current',
|
||||
};
|
||||
return {simpleSiteDir, defaultOptions, defaultContext, vCurrent};
|
||||
|
@ -218,6 +219,7 @@ describe('readVersionsMetadata', () => {
|
|||
path: '/docs/next',
|
||||
banner: 'unreleased',
|
||||
badge: true,
|
||||
noIndex: false,
|
||||
className: 'docs-version-current',
|
||||
};
|
||||
|
||||
|
@ -242,6 +244,7 @@ describe('readVersionsMetadata', () => {
|
|||
path: '/docs',
|
||||
banner: null,
|
||||
badge: true,
|
||||
noIndex: false,
|
||||
className: 'docs-version-1.0.1',
|
||||
};
|
||||
|
||||
|
@ -266,6 +269,7 @@ describe('readVersionsMetadata', () => {
|
|||
path: '/docs/1.0.0',
|
||||
banner: 'unmaintained',
|
||||
badge: true,
|
||||
noIndex: false,
|
||||
className: 'docs-version-1.0.0',
|
||||
};
|
||||
|
||||
|
@ -290,6 +294,7 @@ describe('readVersionsMetadata', () => {
|
|||
path: '/docs/withSlugs',
|
||||
banner: 'unmaintained',
|
||||
badge: true,
|
||||
noIndex: false,
|
||||
className: 'docs-version-withSlugs',
|
||||
};
|
||||
|
||||
|
@ -657,6 +662,7 @@ describe('readVersionsMetadata', () => {
|
|||
path: '/communityBasePath/next',
|
||||
banner: 'unreleased',
|
||||
badge: true,
|
||||
noIndex: false,
|
||||
className: 'docs-version-current',
|
||||
};
|
||||
|
||||
|
@ -681,6 +687,7 @@ describe('readVersionsMetadata', () => {
|
|||
path: '/communityBasePath',
|
||||
banner: null,
|
||||
badge: true,
|
||||
noIndex: false,
|
||||
className: 'docs-version-1.0.0',
|
||||
};
|
||||
|
||||
|
|
|
@ -122,6 +122,13 @@ export function getVersionBadge({
|
|||
return options.versions[versionName]?.badge ?? defaultVersionBadge;
|
||||
}
|
||||
|
||||
export function getVersionNoIndex({
|
||||
versionName,
|
||||
options,
|
||||
}: VersionContext): VersionMetadata['noIndex'] {
|
||||
return options.versions[versionName]?.noIndex ?? false;
|
||||
}
|
||||
|
||||
function getVersionClassName({
|
||||
versionName,
|
||||
options,
|
||||
|
@ -179,6 +186,7 @@ async function createVersionMetadata(
|
|||
label: getVersionLabel(context),
|
||||
banner: getVersionBanner(context),
|
||||
badge: getVersionBadge(context),
|
||||
noIndex: getVersionNoIndex(context),
|
||||
className: getVersionClassName(context),
|
||||
path: routePath,
|
||||
tagsPath: normalizeUrl([routePath, options.tagsBasePath]),
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
"tslib": "^2.4.0",
|
||||
"webpack": "^5.73.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
"react-dom": "^16.8.4 || ^17.0.0"
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
"react-json-view": "^1.21.3",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
"react-dom": "^16.8.4 || ^17.0.0"
|
||||
|
|
|
@ -23,9 +23,6 @@
|
|||
"@docusaurus/utils-validation": "2.0.1",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
"react-dom": "^16.8.4 || ^17.0.0"
|
||||
|
|
|
@ -23,9 +23,6 @@
|
|||
"@docusaurus/utils-validation": "2.0.1",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
"react-dom": "^16.8.4 || ^17.0.0"
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.0.1",
|
||||
"@docusaurus/types": "2.0.0-beta.21",
|
||||
"fs-extra": "^10.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
|
|
@ -28,9 +28,6 @@
|
|||
"sitemap": "^7.1.1",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
"react-dom": "^16.8.4 || ^17.0.0"
|
||||
|
|
|
@ -158,7 +158,10 @@ describe('createSitemap', () => {
|
|||
meta: {
|
||||
// @ts-expect-error: bad lib def
|
||||
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 {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(
|
||||
siteConfig: DocusaurusConfig,
|
||||
routesPaths: string[],
|
||||
|
@ -27,18 +61,15 @@ export default async function createSitemap(
|
|||
|
||||
const ignoreMatcher = createMatcher(ignorePatterns);
|
||||
|
||||
const includedRoutes = routesPaths.filter((route) => {
|
||||
if (route.endsWith('404.html') || ignoreMatcher(route)) {
|
||||
return false;
|
||||
}
|
||||
// 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) => tag.props.name === 'robots' && tag.props.content === 'noindex',
|
||||
function isRouteExcluded(route: string) {
|
||||
return (
|
||||
route.endsWith('404.html') ||
|
||||
ignoreMatcher(route) ||
|
||||
isNoIndexMetaRoute({head, route})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const includedRoutes = routesPaths.filter((route) => !isRouteExcluded(route));
|
||||
|
||||
if (includedRoutes.length === 0) {
|
||||
return null;
|
||||
|
|
|
@ -87,7 +87,7 @@ export default function preset(
|
|||
throw new Error(
|
||||
`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"
|
||||
},
|
||||
"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/nprogress": "^0.2.0",
|
||||
"@types/prismjs": "^1.26.0",
|
||||
|
|
|
@ -28,6 +28,14 @@ export default function getSwizzleConfig(): SwizzleConfig {
|
|||
description:
|
||||
'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: {
|
||||
actions: {
|
||||
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;
|
||||
}
|
||||
|
||||
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' {
|
||||
export default function BackToTopButton(): JSX.Element;
|
||||
}
|
||||
|
@ -320,7 +336,7 @@ declare module '@theme/DocCardList' {
|
|||
import type {PropSidebarItem} from '@docusaurus/plugin-content-docs';
|
||||
|
||||
export interface Props {
|
||||
readonly items: PropSidebarItem[];
|
||||
readonly items?: PropSidebarItem[];
|
||||
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 clsx from 'clsx';
|
||||
import {useThemeConfig} from '@docusaurus/theme-common';
|
||||
import {useAnnouncementBar} from '@docusaurus/theme-common/internal';
|
||||
import {translate} from '@docusaurus/Translate';
|
||||
import IconClose from '@theme/Icon/Close';
|
||||
import AnnouncementBarCloseButton from '@theme/AnnouncementBar/CloseButton';
|
||||
import AnnouncementBarContent from '@theme/AnnouncementBar/Content';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
|
||||
export default function AnnouncementBar(): JSX.Element | null {
|
||||
const {isActive, close} = useAnnouncementBar();
|
||||
const {announcementBar} = useThemeConfig();
|
||||
|
||||
const {isActive, close} = useAnnouncementBar();
|
||||
if (!isActive) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {content, backgroundColor, textColor, isCloseable} = announcementBar!;
|
||||
|
||||
const {backgroundColor, textColor, isCloseable} = announcementBar!;
|
||||
return (
|
||||
<div
|
||||
className={styles.announcementBar}
|
||||
style={{backgroundColor, color: textColor}}
|
||||
role="banner">
|
||||
{isCloseable && <div className={styles.announcementBarPlaceholder} />}
|
||||
<div
|
||||
className={styles.announcementBarContent}
|
||||
// Developer provided the HTML, so assume it's safe.
|
||||
// eslint-disable-next-line react/no-danger
|
||||
dangerouslySetInnerHTML={{__html: content}}
|
||||
/>
|
||||
{isCloseable ? (
|
||||
<button
|
||||
type="button"
|
||||
className={clsx('clean-btn close', styles.announcementBarClose)}
|
||||
<AnnouncementBarContent className={styles.announcementBarContent} />
|
||||
{isCloseable && (
|
||||
<AnnouncementBarCloseButton
|
||||
onClick={close}
|
||||
aria-label={translate({
|
||||
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}
|
||||
className={styles.announcementBarClose}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
height: var(--docusaurus-announcement-bar-height);
|
||||
background-color: var(--ifm-color-white);
|
||||
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 {
|
||||
|
@ -29,15 +30,10 @@ html[data-announcement-bar-initially-dismissed='true'] .announcementBar {
|
|||
.announcementBarClose {
|
||||
flex: 0 0 30px;
|
||||
align-self: stretch;
|
||||
padding: 0;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.announcementBarContent {
|
||||
flex: 1 1 auto;
|
||||
font-size: 85%;
|
||||
text-align: center;
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
@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) {
|
||||
:root {
|
||||
--docusaurus-announcement-bar-height: 30px;
|
||||
|
|
|
@ -35,6 +35,7 @@ the background in custom CSS file due bug https://github.com/facebook/docusaurus
|
|||
left: 0;
|
||||
padding: 0 var(--ifm-pre-padding);
|
||||
background: var(--ifm-pre-background);
|
||||
overflow-wrap: normal;
|
||||
}
|
||||
|
||||
.codeLineNumber::before {
|
||||
|
|
|
@ -7,25 +7,27 @@
|
|||
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import {findFirstCategoryLink} from '@docusaurus/theme-common/internal';
|
||||
import {
|
||||
useCurrentSidebarCategory,
|
||||
filterDocCardListItems,
|
||||
} from '@docusaurus/theme-common';
|
||||
import DocCard from '@theme/DocCard';
|
||||
import type {Props} from '@theme/DocCardList';
|
||||
import type {PropSidebarItem} from '@docusaurus/plugin-content-docs';
|
||||
|
||||
// Filter categories that don't have a link.
|
||||
function filterItems(items: PropSidebarItem[]): PropSidebarItem[] {
|
||||
return items.filter((item) => {
|
||||
if (item.type === 'category') {
|
||||
return !!findFirstCategoryLink(item);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
function DocCardListForCurrentSidebarCategory({className}: Props) {
|
||||
const category = useCurrentSidebarCategory();
|
||||
return <DocCardList items={category.items} className={className} />;
|
||||
}
|
||||
|
||||
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 (
|
||||
<section className={clsx('row', className)}>
|
||||
{filterItems(items).map((item, index) => (
|
||||
{filteredItems.map((item, index) => (
|
||||
<article key={index} className="col col--6 margin-bottom--lg">
|
||||
<DocCard item={item} />
|
||||
</article>
|
||||
|
|
|
@ -7,7 +7,11 @@
|
|||
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import {HtmlClassNameProvider, ThemeClassNames} from '@docusaurus/theme-common';
|
||||
import {
|
||||
HtmlClassNameProvider,
|
||||
ThemeClassNames,
|
||||
PageMetadata,
|
||||
} from '@docusaurus/theme-common';
|
||||
import {
|
||||
docVersionSearchTag,
|
||||
DocsSidebarProvider,
|
||||
|
@ -19,13 +23,8 @@ import NotFound from '@theme/NotFound';
|
|||
import SearchMetadata from '@theme/SearchMetadata';
|
||||
import type {Props} from '@theme/DocPage';
|
||||
|
||||
export default function DocPage(props: Props): JSX.Element {
|
||||
function DocPageMetadata(props: Props): JSX.Element {
|
||||
const {versionMetadata} = props;
|
||||
const currentDocRouteMetadata = useDocRouteMetadata(props);
|
||||
if (!currentDocRouteMetadata) {
|
||||
return <NotFound />;
|
||||
}
|
||||
const {docElement, sidebarName, sidebarItems} = currentDocRouteMetadata;
|
||||
return (
|
||||
<>
|
||||
<SearchMetadata
|
||||
|
@ -35,6 +34,25 @@ export default function DocPage(props: Props): JSX.Element {
|
|||
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
|
||||
className={clsx(
|
||||
// TODO: it should be removed from here
|
||||
|
|
|
@ -136,7 +136,7 @@ export default function DocSidebarItemCategory({
|
|||
useEffect(() => {
|
||||
if (
|
||||
collapsible &&
|
||||
expandedItem &&
|
||||
expandedItem != null &&
|
||||
expandedItem !== index &&
|
||||
autoCollapseCategories
|
||||
) {
|
||||
|
|
|
@ -24,7 +24,7 @@ export default function DocSidebarItemLink({
|
|||
index,
|
||||
...props
|
||||
}: Props): JSX.Element {
|
||||
const {href, label, className} = item;
|
||||
const {href, label, className, autoAddBaseUrl} = item;
|
||||
const isActive = isActiveSidebarItem(item, activePath);
|
||||
const isInternalLink = isInternalUrl(href);
|
||||
return (
|
||||
|
@ -44,6 +44,7 @@ export default function DocSidebarItemLink({
|
|||
'menu__link--active': isActive,
|
||||
},
|
||||
)}
|
||||
autoAddBaseUrl={autoAddBaseUrl}
|
||||
aria-current={isActive ? 'page' : undefined}
|
||||
to={href}
|
||||
{...(isInternalLink && {
|
||||
|
|
|
@ -34,6 +34,7 @@ export default function LocaleDropdownNavbarItem({
|
|||
})}`;
|
||||
return {
|
||||
label: localeConfigs[locale]!.label,
|
||||
lang: localeConfigs[locale]!.htmlLang,
|
||||
to,
|
||||
target: '_self',
|
||||
autoAddBaseUrl: false,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import Translate from '@docusaurus/Translate';
|
||||
import Translate, {translate} from '@docusaurus/Translate';
|
||||
import {useSkipToContent} from '@docusaurus/theme-common/internal';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
|
@ -14,7 +14,10 @@ import styles from './styles.module.css';
|
|||
export default function SkipToContent(): JSX.Element {
|
||||
const {containerRef, handleSkip} = useSkipToContent();
|
||||
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 */}
|
||||
<a href="#" className={styles.skipToContent} onClick={handleSkip}>
|
||||
<Translate
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
.tagRegular {
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.3rem 0.5rem;
|
||||
padding: 0.2rem 0.5rem 0.3rem;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,10 @@ export {createStorageSlot, listStorageKeys} from './utils/storageUtils';
|
|||
|
||||
export {useContextualSearchFilters} from './utils/searchUtils';
|
||||
|
||||
export {useCurrentSidebarCategory} from './utils/docsUtils';
|
||||
export {
|
||||
useCurrentSidebarCategory,
|
||||
filterDocCardListItems,
|
||||
} from './utils/docsUtils';
|
||||
|
||||
export {usePluralForm} from './utils/usePluralForm';
|
||||
|
||||
|
|
|
@ -441,26 +441,87 @@ describe('useCurrentSidebarCategory', () => {
|
|||
</DocsSidebarProvider>
|
||||
),
|
||||
}).result.current;
|
||||
it('works', () => {
|
||||
const category: PropSidebarItemCategory = {
|
||||
type: 'category',
|
||||
label: 'Category',
|
||||
|
||||
it('works for sidebar category', () => {
|
||||
const category: PropSidebarItemCategory = testCategory({
|
||||
href: '/cat',
|
||||
collapsible: true,
|
||||
collapsed: false,
|
||||
items: [
|
||||
{type: 'link', href: '/cat/foo', label: 'Foo'},
|
||||
{type: 'link', href: '/cat/bar', label: 'Bar'},
|
||||
{type: 'link', href: '/baz', label: 'Baz'},
|
||||
],
|
||||
};
|
||||
const mockUseCurrentSidebarCategory = createUseCurrentSidebarCategoryMock([
|
||||
{type: 'link', href: '/cat/fake', label: 'Fake'},
|
||||
});
|
||||
const sidebar: PropSidebar = [
|
||||
testLink(),
|
||||
testLink(),
|
||||
category,
|
||||
]);
|
||||
testCategory(),
|
||||
];
|
||||
|
||||
const mockUseCurrentSidebarCategory =
|
||||
createUseCurrentSidebarCategoryMock(sidebar);
|
||||
|
||||
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', () => {
|
||||
const category: PropSidebarItemCategory = {
|
||||
type: 'category',
|
||||
|
|
|
@ -110,15 +110,18 @@ export function useCurrentSidebarCategory(): PropSidebarItemCategory {
|
|||
if (!sidebar) {
|
||||
throw new Error('Unexpected: cant find current sidebar in context');
|
||||
}
|
||||
const category = findSidebarCategory(sidebar.items, (item) =>
|
||||
isSamePath(item.href, pathname),
|
||||
);
|
||||
if (!category) {
|
||||
const categoryBreadcrumbs = getSidebarBreadcrumbs({
|
||||
sidebarItems: sidebar.items,
|
||||
pathname,
|
||||
onlyCategories: true,
|
||||
});
|
||||
const deepestCategory = categoryBreadcrumbs.slice(-1)[0];
|
||||
if (!deepestCategory) {
|
||||
throw new Error(
|
||||
`${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) =>
|
||||
|
@ -149,6 +152,55 @@ export function isActiveSidebarItem(
|
|||
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.
|
||||
* Returns `null` if there's no sidebar or breadcrumbs are disabled.
|
||||
|
@ -157,31 +209,10 @@ export function useSidebarBreadcrumbs(): PropSidebarBreadcrumbsItem[] | null {
|
|||
const sidebar = useDocsSidebar();
|
||||
const {pathname} = useLocation();
|
||||
const breadcrumbsOption = useActivePlugin()?.pluginData.breadcrumbs;
|
||||
|
||||
if (breadcrumbsOption === false || !sidebar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
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();
|
||||
return getSidebarBreadcrumbs({sidebarItems: sidebar.items, pathname});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -332,3 +363,18 @@ export function useDocRouteMetadata({
|
|||
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.seeAll": "Xem tất cả {count} kết quả",
|
||||
"theme.SearchModal.errorScreen.helpText": "You might want to check your network connection.",
|
||||
"theme.SearchModal.errorScreen.titleText": "Unable to fetch results",
|
||||
"theme.SearchModal.footer.closeKeyAriaLabel": "Escape key",
|
||||
"theme.SearchModal.footer.closeText": "to close",
|
||||
"theme.SearchModal.footer.navigateDownKeyAriaLabel": "Arrow down",
|
||||
"theme.SearchModal.footer.navigateText": "to navigate",
|
||||
"theme.SearchModal.footer.navigateUpKeyAriaLabel": "Arrow up",
|
||||
"theme.SearchModal.footer.searchByText": "Search by",
|
||||
"theme.SearchModal.footer.selectKeyAriaLabel": "Enter key",
|
||||
"theme.SearchModal.footer.selectText": "to select",
|
||||
"theme.SearchModal.noResultsScreen.noResultsText": "No results for",
|
||||
"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": "Let us know.",
|
||||
"theme.SearchModal.noResultsScreen.reportMissingResultsText": "Believe this query should return results?",
|
||||
"theme.SearchModal.noResultsScreen.suggestedQueryText": "Try searching for",
|
||||
"theme.SearchModal.placeholder": "Search docs",
|
||||
"theme.SearchModal.searchBox.cancelButtonText": "Cancel",
|
||||
"theme.SearchModal.searchBox.resetButtonTitle": "Clear the query",
|
||||
"theme.SearchModal.startScreen.favoriteSearchesTitle": "Favorite",
|
||||
"theme.SearchModal.startScreen.noRecentSearchesText": "No recent searches",
|
||||
"theme.SearchModal.startScreen.recentSearchesTitle": "Recent",
|
||||
"theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": "Remove this search from favorites",
|
||||
"theme.SearchModal.startScreen.removeRecentSearchButtonTitle": "Remove this search from history",
|
||||
"theme.SearchModal.startScreen.saveRecentSearchButtonTitle": "Save this search",
|
||||
"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": "Không thể tìm nạp dữ liệu",
|
||||
"theme.SearchModal.footer.closeKeyAriaLabel": "Phím thoát",
|
||||
"theme.SearchModal.footer.closeText": "để đóng",
|
||||
"theme.SearchModal.footer.navigateDownKeyAriaLabel": "Mũi tên xuống",
|
||||
"theme.SearchModal.footer.navigateText": "để điều hướng",
|
||||
"theme.SearchModal.footer.navigateUpKeyAriaLabel": "Mũi tên lên",
|
||||
"theme.SearchModal.footer.searchByText": "Tìm kiếm theo",
|
||||
"theme.SearchModal.footer.selectKeyAriaLabel": "Nhập khóa",
|
||||
"theme.SearchModal.footer.selectText": "để chọn",
|
||||
"theme.SearchModal.noResultsScreen.noResultsText": "Không có kết quả dành cho",
|
||||
"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": "Hãy để chúng tôi biết.",
|
||||
"theme.SearchModal.noResultsScreen.reportMissingResultsText": "Tin rằng truy vấn này sẽ trả về kết quả?",
|
||||
"theme.SearchModal.noResultsScreen.suggestedQueryText": "Thử tìm kiếm",
|
||||
"theme.SearchModal.placeholder": "Tìm kiếm tài liệu",
|
||||
"theme.SearchModal.searchBox.cancelButtonText": "Hủy bỏ",
|
||||
"theme.SearchModal.searchBox.resetButtonTitle": "Xóa truy vấn",
|
||||
"theme.SearchModal.startScreen.favoriteSearchesTitle": "Yêu thích",
|
||||
"theme.SearchModal.startScreen.noRecentSearchesText": "Không có tìm kiếm nào gần đây",
|
||||
"theme.SearchModal.startScreen.recentSearchesTitle": "Gần đây",
|
||||
"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": "Xóa tìm kiếm này khỏi lịch sử",
|
||||
"theme.SearchModal.startScreen.saveRecentSearchButtonTitle": "Lưu tìm kiếm này",
|
||||
"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.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. */
|
||||
label: string;
|
||||
/**
|
||||
* BCP 47 language tag to use in `<html lang="...">` and in
|
||||
* `<link ... hreflang="...">`
|
||||
* BCP 47 language tag to use in:
|
||||
* - `<html lang="...">` (or any other DOM tag name)
|
||||
* - `<link ... hreflang="...">`
|
||||
*/
|
||||
htmlLang: string;
|
||||
/** Used to select the locale's CSS and html meta attribute. */
|
||||
|
|
|
@ -86,7 +86,7 @@ export function getFileLoaderUtils(): FileLoaderUtils {
|
|||
*/
|
||||
images: () => ({
|
||||
use: [loaders.url({folder: 'images'})],
|
||||
test: /\.(?:ico|jpe?g|png|gif|webp)(?:\?.*)?$/i,
|
||||
test: /\.(?:ico|jpe?g|png|gif|webp|avif)(?:\?.*)?$/i,
|
||||
}),
|
||||
|
||||
fonts: () => ({
|
||||
|
@ -100,7 +100,7 @@ export function getFileLoaderUtils(): FileLoaderUtils {
|
|||
*/
|
||||
media: () => ({
|
||||
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: () => ({
|
||||
|
|
|
@ -12,7 +12,7 @@ import useBaseUrl from '@docusaurus/useBaseUrl';
|
|||
|
||||
export default function SiteMetadataDefaults(): JSX.Element {
|
||||
const {
|
||||
siteConfig: {favicon, title},
|
||||
siteConfig: {favicon, title, noIndex},
|
||||
i18n: {currentLocale, localeConfigs},
|
||||
} = useDocusaurusContext();
|
||||
const faviconUrl = useBaseUrl(favicon);
|
||||
|
@ -20,9 +20,17 @@ export default function SiteMetadataDefaults(): JSX.Element {
|
|||
|
||||
return (
|
||||
<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} />
|
||||
<title>{title}</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} />}
|
||||
</Head>
|
||||
);
|
||||
|
|
|
@ -17,7 +17,9 @@ import {matchRoutes} from 'react-router-config';
|
|||
* @returns Promise object represents whether pathname has been preloaded
|
||||
*/
|
||||
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?.()));
|
||||
}
|
||||
|
|
|
@ -29,6 +29,14 @@ export type WriteTranslationsCLIOptions = Pick<
|
|||
> &
|
||||
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!
|
||||
* 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
|
||||
*/
|
||||
async function getExtraSourceCodeFilePaths(): Promise<string[]> {
|
||||
try {
|
||||
const themeCommonSourceDir = path.dirname(
|
||||
require.resolve('@docusaurus/theme-common/lib'),
|
||||
);
|
||||
return globSourceCodeFilePaths([themeCommonSourceDir]);
|
||||
} catch {
|
||||
const themeCommonLibDir = resolveThemeCommonLibDir();
|
||||
if (!themeCommonLibDir) {
|
||||
return []; // User may not use a Docusaurus official theme? Quite unlikely...
|
||||
}
|
||||
return globSourceCodeFilePaths([themeCommonLibDir]);
|
||||
}
|
||||
|
||||
async function writePluginTranslationFiles({
|
||||
|
@ -108,6 +113,7 @@ Available locales are: ${context.i18n.locales.join(',')}.`,
|
|||
babelOptions,
|
||||
await getExtraSourceCodeFilePaths(),
|
||||
);
|
||||
|
||||
const defaultCodeMessages = await getPluginsDefaultCodeTranslationMessages(
|
||||
plugins,
|
||||
);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="generator" content="Docusaurus">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<%= htmlWebpackPlugin.options.headTags %>
|
||||
|
|
|
@ -10,15 +10,11 @@ export default `
|
|||
<html <%~ it.htmlAttributes %>>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="generator" content="Docusaurus v<%= it.version %>">
|
||||
<% if (it.noIndex) { %>
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<% } %>
|
||||
<%~ it.headTags %>
|
||||
<% it.metaAttributes.forEach((metaAttribute) => { %>
|
||||
<%~ metaAttribute %>
|
||||
<% }); %>
|
||||
<%~ it.headTags %>
|
||||
<% it.stylesheets.forEach((stylesheet) => { %>
|
||||
<link rel="stylesheet" href="<%= it.baseUrl %><%= stylesheet %>" />
|
||||
<% }); %>
|
||||
|
|
|
@ -249,3 +249,21 @@ echo "short_initially_hidden_string"
|
|||
</Tabs>
|
||||
|
||||
[// 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)
|
||||
- [Tabs tests](/tests/pages/tabs-tests)
|
||||
- [z-index tests](/tests/pages/z-index-tests)
|
||||
- [Head metadata tests](/tests/pages/head-metadata)
|
||||
|
|
|
@ -71,10 +71,27 @@ const sidebars = {
|
|||
],
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
label: 'External link',
|
||||
href: 'https://github.com/facebook/docusaurus',
|
||||
type: 'category',
|
||||
label: 'Link tests',
|
||||
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',
|
||||
|
|
|
@ -26,6 +26,11 @@ const dogfoodingPluginInstances = [
|
|||
id: 'docs-tests',
|
||||
routeBasePath: '/tests/docs',
|
||||
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
|
||||
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
|
||||
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😉
|
||||
|
|
|
@ -157,7 +157,7 @@ module.exports = {
|
|||
- `localeConfigs`: Individual options for each locale.
|
||||
- `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.
|
||||
- `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`).
|
||||
- `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 %>>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="generator" content="Docusaurus v<%= it.version %>">
|
||||
<% if (it.noIndex) { %>
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<% } %>
|
||||
<%~ it.headTags %>
|
||||
<% it.metaAttributes.forEach((metaAttribute) => { %>
|
||||
<%~ metaAttribute %>
|
||||
<% }); %>
|
||||
<%~ it.headTags %>
|
||||
<% it.stylesheets.forEach((stylesheet) => { %>
|
||||
<link rel="stylesheet" href="<%= it.baseUrl %><%= stylesheet %>" />
|
||||
<% }); %>
|
||||
|
|
|
@ -142,23 +142,25 @@ type CategoryIndexMatcher = (param: {
|
|||
#### `VersionsConfig` {#VersionsConfig}
|
||||
|
||||
```ts
|
||||
type VersionsConfig = {
|
||||
[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' | 'unreleased' | 'unmaintained';
|
||||
/** 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;
|
||||
};
|
||||
type VersionConfig = {
|
||||
/**
|
||||
* 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' | 'unreleased' | 'unmaintained';
|
||||
/** 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;
|
||||
};
|
||||
|
||||
type VersionsConfig = {[versionName: string]: VersionConfig};
|
||||
```
|
||||
|
||||
### Example configuration {#ex-config}
|
||||
|
|
|
@ -35,9 +35,8 @@ This section serves as an overview of miscellaneous features of the doc sidebar.
|
|||
|
||||
```mdx-code-block
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
||||
|
||||
<DocCardList items={useCurrentSidebarCategory().items}/>
|
||||
<DocCardList />
|
||||
```
|
||||
|
||||
## Default sidebar {#default-sidebar}
|
||||
|
|
|
@ -8,6 +8,7 @@ slug: /sidebar/items
|
|||
```mdx-code-block
|
||||
import Tabs from '@theme/Tabs';
|
||||
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.
|
||||
|
@ -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}
|
||||
|
||||
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 {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
||||
|
||||
In this section, we will introduce the following concepts:
|
||||
|
||||
<DocCardList items={useCurrentSidebarCategory().items}/>
|
||||
<DocCardList />
|
||||
```
|
||||
|
||||
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}
|
||||
|
||||
|
|
|
@ -65,11 +65,9 @@ import LiteYouTubeEmbed from 'react-lite-youtube-embed';
|
|||
</div>
|
||||
```
|
||||
|
||||
## Disclaimer {#disclaimer}
|
||||
## Migrating from v1 {#migrating-from-v1}
|
||||
|
||||
Docusaurus v2 is **beta** but already quite stable and widely used.
|
||||
|
||||
We highly encourage you to **use Docusaurus v2 over Docusaurus v1**, as Docusaurus v1 will be deprecated soon.
|
||||
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.
|
||||
|
||||
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:**
|
||||
|
||||
- :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}
|
||||
|
||||
|
|
|
@ -124,7 +124,11 @@ Read more about the robots file in [the Google documentation](https://developers
|
|||
|
||||
:::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.
|
||||
|
||||
:::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}
|
||||
|
||||
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,
|
||||
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>
|
||||
```
|
||||
|
||||
## Disclaimer {#disclaimer}
|
||||
## Migrating from v1 {#migrating-from-v1}
|
||||
|
||||
Docusaurus v2 is **beta** but already quite stable and widely used.
|
||||
|
||||
We highly encourage you to **use Docusaurus v2 over Docusaurus v1**, as Docusaurus v1 will be deprecated soon.
|
||||
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.
|
||||
|
||||
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:**
|
||||
|
||||
- :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}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue