mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 15:47:23 +02:00
feat: doc tags (same as blog tags) (#3646)
* [v2] tags to doc, same as tags to blog - [IN PROGRESS] - Addition of plugin-content-docs - Addition of DocTagsListPage in `docusaurus-theme-classic` ! Error exists for this commit towards the theme aspect and help required. Commit towards #3434 * docs: make tags list page work * temp: disable onBrokenLinks * theme bootstrap: create DocTagsListPage * DocTagsPage added and functionality too - individual doc tag page added to show docs for that specific tag * Added all Docs Tags Link * add some shared tag utils * move tag tests to _dogfooding * fix type * fix some tests * fix blog test * refactor blog post tags handling * better yaml tag examples * better dogfood md files * refactor and factorize theme tag components * finish DocTagDocListPage * Extract DocItemFooter + add inline tag list * minor fix * better typings * fix versions.test.ts tests * add tests for doc tags * fix tests * test toTagDocListProp * move shared theme code to tagUtils * Add new theme translation keys * move common theme code to tagUtils + add tests * update-code-translations should handle theme-common * update french translation * revert add translation * fix pluralization problem in theme.docs.tagDocListPageTitle * add theme component configuration options * add more tags tests * add documentation for docs tagging Co-authored-by: slorber <lorber.sebastien@gmail.com>
This commit is contained in:
parent
f666de7e59
commit
f9c79cbd58
81 changed files with 1874 additions and 381 deletions
|
@ -33,6 +33,11 @@ module.exports = {
|
||||||
},
|
},
|
||||||
setupFiles: ['./jest/stylelint-rule-test.js', './jest/polyfills.js'],
|
setupFiles: ['./jest/stylelint-rule-test.js', './jest/polyfills.js'],
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
|
// TODO we need to allow Jest to resolve core Webpack aliases automatically
|
||||||
'@docusaurus/router': 'react-router-dom',
|
'@docusaurus/router': 'react-router-dom',
|
||||||
|
'@docusaurus/Translate': '@docusaurus/core/lib/client/exports/Translate',
|
||||||
|
'@docusaurus/Interpolate':
|
||||||
|
'@docusaurus/core/lib/client/exports/Interpolate',
|
||||||
|
'@generated/codeTranslations': '<rootDir>/jest/emptyModule.js',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
8
jest/emptyModule.js
Normal file
8
jest/emptyModule.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = {};
|
|
@ -9,15 +9,16 @@ import {
|
||||||
JoiFrontMatter as Joi, // Custom instance for frontmatter
|
JoiFrontMatter as Joi, // Custom instance for frontmatter
|
||||||
URISchema,
|
URISchema,
|
||||||
validateFrontMatter,
|
validateFrontMatter,
|
||||||
|
FrontMatterTagsSchema,
|
||||||
} from '@docusaurus/utils-validation';
|
} from '@docusaurus/utils-validation';
|
||||||
import {Tag} from './types';
|
import type {FrontMatterTag} from '@docusaurus/utils';
|
||||||
|
|
||||||
export type BlogPostFrontMatter = {
|
export type BlogPostFrontMatter = {
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
id?: string;
|
id?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
tags?: (string | Tag)[];
|
tags?: FrontMatterTag[];
|
||||||
slug?: string;
|
slug?: string;
|
||||||
draft?: boolean;
|
draft?: boolean;
|
||||||
date?: Date | string; // Yaml automagically convert some string patterns as Date, but not all
|
date?: Date | string; // Yaml automagically convert some string patterns as Date, but not all
|
||||||
|
@ -38,23 +39,11 @@ export type BlogPostFrontMatter = {
|
||||||
/* eslint-enable camelcase */
|
/* eslint-enable camelcase */
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE: we don't add any default value on purpose here
|
|
||||||
// We don't want default values to magically appear in doc metadatas and props
|
|
||||||
// While the user did not provide those values explicitly
|
|
||||||
// We use default values in code instead
|
|
||||||
const BlogTagSchema = Joi.alternatives().try(
|
|
||||||
Joi.string().required(),
|
|
||||||
Joi.object<Tag>({
|
|
||||||
label: Joi.string().required(),
|
|
||||||
permalink: Joi.string().required(),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
const BlogFrontMatterSchema = Joi.object<BlogPostFrontMatter>({
|
const BlogFrontMatterSchema = Joi.object<BlogPostFrontMatter>({
|
||||||
id: Joi.string(),
|
id: Joi.string(),
|
||||||
title: Joi.string().allow(''),
|
title: Joi.string().allow(''),
|
||||||
description: Joi.string().allow(''),
|
description: Joi.string().allow(''),
|
||||||
tags: Joi.array().items(BlogTagSchema),
|
tags: FrontMatterTagsSchema,
|
||||||
draft: Joi.boolean(),
|
draft: Joi.boolean(),
|
||||||
date: Joi.date().raw(),
|
date: Joi.date().raw(),
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
BlogPost,
|
BlogPost,
|
||||||
BlogContentPaths,
|
BlogContentPaths,
|
||||||
BlogMarkdownLoaderOptions,
|
BlogMarkdownLoaderOptions,
|
||||||
|
BlogTags,
|
||||||
} from './types';
|
} from './types';
|
||||||
import {
|
import {
|
||||||
parseMarkdownFile,
|
parseMarkdownFile,
|
||||||
|
@ -26,6 +27,8 @@ import {
|
||||||
posixPath,
|
posixPath,
|
||||||
replaceMarkdownLinks,
|
replaceMarkdownLinks,
|
||||||
Globby,
|
Globby,
|
||||||
|
normalizeFrontMatterTags,
|
||||||
|
groupTaggedItems,
|
||||||
} from '@docusaurus/utils';
|
} from '@docusaurus/utils';
|
||||||
import {LoadContext} from '@docusaurus/types';
|
import {LoadContext} from '@docusaurus/types';
|
||||||
import {validateBlogPostFrontMatter} from './blogFrontMatter';
|
import {validateBlogPostFrontMatter} from './blogFrontMatter';
|
||||||
|
@ -43,6 +46,20 @@ export function getSourceToPermalink(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getBlogTags(blogPosts: BlogPost[]): BlogTags {
|
||||||
|
const groups = groupTaggedItems(
|
||||||
|
blogPosts,
|
||||||
|
(blogPost) => blogPost.metadata.tags,
|
||||||
|
);
|
||||||
|
return mapValues(groups, (group) => {
|
||||||
|
return {
|
||||||
|
name: group.tag.label,
|
||||||
|
items: group.items.map((item) => item.id),
|
||||||
|
permalink: group.tag.permalink,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const DATE_FILENAME_REGEX = /^(?<date>\d{4}[-/]\d{1,2}[-/]\d{1,2})[-/]?(?<text>.*?)(\/index)?.mdx?$/;
|
const DATE_FILENAME_REGEX = /^(?<date>\d{4}[-/]\d{1,2}[-/]\d{1,2})[-/]?(?<text>.*?)(\/index)?.mdx?$/;
|
||||||
|
|
||||||
type ParsedBlogFileName = {
|
type ParsedBlogFileName = {
|
||||||
|
@ -240,6 +257,8 @@ async function processBlogSourceFile(
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tagsBasePath = normalizeUrl([baseUrl, options.routeBasePath, 'tags']); // make this configurable?
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: frontMatter.slug ?? title,
|
id: frontMatter.slug ?? title,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
@ -250,7 +269,7 @@ async function processBlogSourceFile(
|
||||||
description,
|
description,
|
||||||
date,
|
date,
|
||||||
formattedDate,
|
formattedDate,
|
||||||
tags: frontMatter.tags ?? [],
|
tags: normalizeFrontMatterTags(tagsBasePath, frontMatter.tags),
|
||||||
readingTime: showReadingTime ? readingTime(content).minutes : undefined,
|
readingTime: showReadingTime ? readingTime(content).minutes : undefined,
|
||||||
truncated: truncateMarker?.test(content) || false,
|
truncated: truncateMarker?.test(content) || false,
|
||||||
},
|
},
|
||||||
|
|
|
@ -22,7 +22,7 @@ import {
|
||||||
STATIC_DIR_NAME,
|
STATIC_DIR_NAME,
|
||||||
DEFAULT_PLUGIN_ID,
|
DEFAULT_PLUGIN_ID,
|
||||||
} from '@docusaurus/core/lib/constants';
|
} from '@docusaurus/core/lib/constants';
|
||||||
import {flatten, take, kebabCase} from 'lodash';
|
import {flatten, take} from 'lodash';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
|
@ -51,6 +51,7 @@ import {
|
||||||
generateBlogPosts,
|
generateBlogPosts,
|
||||||
getContentPathList,
|
getContentPathList,
|
||||||
getSourceToPermalink,
|
getSourceToPermalink,
|
||||||
|
getBlogTags,
|
||||||
} from './blogUtils';
|
} from './blogUtils';
|
||||||
|
|
||||||
export default function pluginContentBlog(
|
export default function pluginContentBlog(
|
||||||
|
@ -65,7 +66,7 @@ export default function pluginContentBlog(
|
||||||
|
|
||||||
const {
|
const {
|
||||||
siteDir,
|
siteDir,
|
||||||
siteConfig: {onBrokenMarkdownLinks},
|
siteConfig: {onBrokenMarkdownLinks, baseUrl},
|
||||||
generatedFilesDir,
|
generatedFilesDir,
|
||||||
i18n: {currentLocale},
|
i18n: {currentLocale},
|
||||||
} = context;
|
} = context;
|
||||||
|
@ -151,17 +152,14 @@ export default function pluginContentBlog(
|
||||||
const postsPerPage =
|
const postsPerPage =
|
||||||
postsPerPageOption === 'ALL' ? totalCount : postsPerPageOption;
|
postsPerPageOption === 'ALL' ? totalCount : postsPerPageOption;
|
||||||
const numberOfPages = Math.ceil(totalCount / postsPerPage);
|
const numberOfPages = Math.ceil(totalCount / postsPerPage);
|
||||||
const {
|
const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
|
||||||
siteConfig: {baseUrl = ''},
|
|
||||||
} = context;
|
|
||||||
const basePageUrl = normalizeUrl([baseUrl, routeBasePath]);
|
|
||||||
|
|
||||||
const blogListPaginated: BlogPaginated[] = [];
|
const blogListPaginated: BlogPaginated[] = [];
|
||||||
|
|
||||||
function blogPaginationPermalink(page: number) {
|
function blogPaginationPermalink(page: number) {
|
||||||
return page > 0
|
return page > 0
|
||||||
? normalizeUrl([basePageUrl, `page/${page + 1}`])
|
? normalizeUrl([baseBlogUrl, `page/${page + 1}`])
|
||||||
: basePageUrl;
|
: baseBlogUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let page = 0; page < numberOfPages; page += 1) {
|
for (let page = 0; page < numberOfPages; page += 1) {
|
||||||
|
@ -186,41 +184,9 @@ export default function pluginContentBlog(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const blogTags: BlogTags = {};
|
const blogTags: BlogTags = getBlogTags(blogPosts);
|
||||||
const tagsPath = normalizeUrl([basePageUrl, 'tags']);
|
|
||||||
blogPosts.forEach((blogPost) => {
|
|
||||||
const {tags} = blogPost.metadata;
|
|
||||||
if (!tags || tags.length === 0) {
|
|
||||||
// TODO: Extract tags out into a separate plugin.
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
|
||||||
blogPost.metadata.tags = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
const tagsPath = normalizeUrl([baseBlogUrl, 'tags']);
|
||||||
blogPost.metadata.tags = tags.map((tag) => {
|
|
||||||
if (typeof tag === 'string') {
|
|
||||||
const normalizedTag = kebabCase(tag);
|
|
||||||
const permalink = normalizeUrl([tagsPath, normalizedTag]);
|
|
||||||
if (!blogTags[normalizedTag]) {
|
|
||||||
blogTags[normalizedTag] = {
|
|
||||||
// Will only use the name of the first occurrence of the tag.
|
|
||||||
name: tag.toLowerCase(),
|
|
||||||
items: [],
|
|
||||||
permalink,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
blogTags[normalizedTag].items.push(blogPost.id);
|
|
||||||
|
|
||||||
return {
|
|
||||||
label: tag,
|
|
||||||
permalink,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return tag;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const blogTagsListPath =
|
const blogTagsListPath =
|
||||||
Object.keys(blogTags).length > 0 ? tagsPath : null;
|
Object.keys(blogTags).length > 0 ? tagsPath : null;
|
||||||
|
@ -348,6 +314,7 @@ export default function pluginContentBlog(
|
||||||
Object.keys(blogTags).map(async (tag) => {
|
Object.keys(blogTags).map(async (tag) => {
|
||||||
const {name, items, permalink} = blogTags[tag];
|
const {name, items, permalink} = blogTags[tag];
|
||||||
|
|
||||||
|
// Refactor all this, see docs implementation
|
||||||
tagsModule[tag] = {
|
tagsModule[tag] = {
|
||||||
allTagsPath: blogTagsListPath,
|
allTagsPath: blogTagsListPath,
|
||||||
slug: tag,
|
slug: tag,
|
||||||
|
@ -535,7 +502,6 @@ export default function pluginContentBlog(
|
||||||
const feedTypes = options.feedOptions.type;
|
const feedTypes = options.feedOptions.type;
|
||||||
const {
|
const {
|
||||||
siteConfig: {title},
|
siteConfig: {title},
|
||||||
baseUrl,
|
|
||||||
} = context;
|
} = context;
|
||||||
const feedsConfig = {
|
const feedsConfig = {
|
||||||
rss: {
|
rss: {
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader';
|
import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader';
|
||||||
import {
|
import type {Tag} from '@docusaurus/utils';
|
||||||
|
import type {
|
||||||
BrokenMarkdownLink,
|
BrokenMarkdownLink,
|
||||||
ContentPaths,
|
ContentPaths,
|
||||||
} from '@docusaurus/utils/lib/markdownLinks';
|
} from '@docusaurus/utils/lib/markdownLinks';
|
||||||
|
@ -96,7 +97,7 @@ export interface MetaData {
|
||||||
description: string;
|
description: string;
|
||||||
date: Date;
|
date: Date;
|
||||||
formattedDate: string;
|
formattedDate: string;
|
||||||
tags: (Tag | string)[];
|
tags: Tag[];
|
||||||
title: string;
|
title: string;
|
||||||
readingTime?: number;
|
readingTime?: number;
|
||||||
prevItem?: Paginator;
|
prevItem?: Paginator;
|
||||||
|
@ -110,11 +111,6 @@ export interface Paginator {
|
||||||
permalink: string;
|
permalink: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Tag {
|
|
||||||
label: string;
|
|
||||||
permalink: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BlogItemsToMetadata {
|
export interface BlogItemsToMetadata {
|
||||||
[key: string]: MetaData;
|
[key: string]: MetaData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,11 @@ id: baz
|
||||||
title: baz
|
title: baz
|
||||||
slug: bazSlug.html
|
slug: bazSlug.html
|
||||||
pagination_label: baz pagination_label
|
pagination_label: baz pagination_label
|
||||||
|
tags:
|
||||||
|
- tag 1
|
||||||
|
- tag-1
|
||||||
|
- label: tag 2
|
||||||
|
permalink: tag2-custom-permalink
|
||||||
---
|
---
|
||||||
|
|
||||||
# Baz markdown title
|
# Baz markdown title
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
id: hello
|
id: hello
|
||||||
title: Hello, World !
|
title: Hello, World !
|
||||||
sidebar_label: Hello sidebar_label
|
sidebar_label: Hello sidebar_label
|
||||||
|
tags: [tag-1, tag 3]
|
||||||
---
|
---
|
||||||
|
|
||||||
Hi, Endilie here :)
|
Hi, Endilie here :)
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
---
|
---
|
||||||
slug: barSlug
|
slug: barSlug
|
||||||
|
tags:
|
||||||
|
- barTag 1
|
||||||
|
- barTag-2
|
||||||
|
- label: barTag 3
|
||||||
|
permalink: barTag-3-permalink
|
||||||
---
|
---
|
||||||
|
|
||||||
This is `next` version of bar.
|
This is `next` version of bar.
|
||||||
|
|
|
@ -177,6 +177,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\"foo\\",
|
\\"sourceDirName\\": \\"foo\\",
|
||||||
\\"slug\\": \\"/foo/bar\\",
|
\\"slug\\": \\"/foo/bar\\",
|
||||||
\\"permalink\\": \\"/docs/foo/bar\\",
|
\\"permalink\\": \\"/docs/foo/bar\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"id\\": \\"bar\\",
|
\\"id\\": \\"bar\\",
|
||||||
|
@ -199,12 +200,30 @@ Object {
|
||||||
\\"sourceDirName\\": \\"foo\\",
|
\\"sourceDirName\\": \\"foo\\",
|
||||||
\\"slug\\": \\"/foo/bazSlug.html\\",
|
\\"slug\\": \\"/foo/bazSlug.html\\",
|
||||||
\\"permalink\\": \\"/docs/foo/bazSlug.html\\",
|
\\"permalink\\": \\"/docs/foo/bazSlug.html\\",
|
||||||
|
\\"tags\\": [
|
||||||
|
{
|
||||||
|
\\"label\\": \\"tag 1\\",
|
||||||
|
\\"permalink\\": \\"/docs/tags/tag-1\\"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"label\\": \\"tag 2\\",
|
||||||
|
\\"permalink\\": \\"/docs/tags/tag2-custom-permalink\\"
|
||||||
|
}
|
||||||
|
],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"id\\": \\"baz\\",
|
\\"id\\": \\"baz\\",
|
||||||
\\"title\\": \\"baz\\",
|
\\"title\\": \\"baz\\",
|
||||||
\\"slug\\": \\"bazSlug.html\\",
|
\\"slug\\": \\"bazSlug.html\\",
|
||||||
\\"pagination_label\\": \\"baz pagination_label\\"
|
\\"pagination_label\\": \\"baz pagination_label\\",
|
||||||
|
\\"tags\\": [
|
||||||
|
\\"tag 1\\",
|
||||||
|
\\"tag-1\\",
|
||||||
|
{
|
||||||
|
\\"label\\": \\"tag 2\\",
|
||||||
|
\\"permalink\\": \\"tag2-custom-permalink\\"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
\\"sidebar\\": \\"docs\\",
|
\\"sidebar\\": \\"docs\\",
|
||||||
\\"previous\\": {
|
\\"previous\\": {
|
||||||
|
@ -226,6 +245,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/headingAsTitle\\",
|
\\"slug\\": \\"/headingAsTitle\\",
|
||||||
\\"permalink\\": \\"/docs/headingAsTitle\\",
|
\\"permalink\\": \\"/docs/headingAsTitle\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {}
|
\\"frontMatter\\": {}
|
||||||
}",
|
}",
|
||||||
|
@ -239,11 +259,25 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/\\",
|
\\"slug\\": \\"/\\",
|
||||||
\\"permalink\\": \\"/docs/\\",
|
\\"permalink\\": \\"/docs/\\",
|
||||||
|
\\"tags\\": [
|
||||||
|
{
|
||||||
|
\\"label\\": \\"tag-1\\",
|
||||||
|
\\"permalink\\": \\"/docs/tags/tag-1\\"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"label\\": \\"tag 3\\",
|
||||||
|
\\"permalink\\": \\"/docs/tags/tag-3\\"
|
||||||
|
}
|
||||||
|
],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"id\\": \\"hello\\",
|
\\"id\\": \\"hello\\",
|
||||||
\\"title\\": \\"Hello, World !\\",
|
\\"title\\": \\"Hello, World !\\",
|
||||||
\\"sidebar_label\\": \\"Hello sidebar_label\\"
|
\\"sidebar_label\\": \\"Hello sidebar_label\\",
|
||||||
|
\\"tags\\": [
|
||||||
|
\\"tag-1\\",
|
||||||
|
\\"tag 3\\"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
\\"sidebar\\": \\"docs\\",
|
\\"sidebar\\": \\"docs\\",
|
||||||
\\"previous\\": {
|
\\"previous\\": {
|
||||||
|
@ -262,6 +296,7 @@ Object {
|
||||||
\\"slug\\": \\"/ipsum\\",
|
\\"slug\\": \\"/ipsum\\",
|
||||||
\\"permalink\\": \\"/docs/ipsum\\",
|
\\"permalink\\": \\"/docs/ipsum\\",
|
||||||
\\"editUrl\\": null,
|
\\"editUrl\\": null,
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"custom_edit_url\\": null
|
\\"custom_edit_url\\": null
|
||||||
|
@ -278,6 +313,7 @@ Object {
|
||||||
\\"slug\\": \\"/lorem\\",
|
\\"slug\\": \\"/lorem\\",
|
||||||
\\"permalink\\": \\"/docs/lorem\\",
|
\\"permalink\\": \\"/docs/lorem\\",
|
||||||
\\"editUrl\\": \\"https://github.com/customUrl/docs/lorem.md\\",
|
\\"editUrl\\": \\"https://github.com/customUrl/docs/lorem.md\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"custom_edit_url\\": \\"https://github.com/customUrl/docs/lorem.md\\",
|
\\"custom_edit_url\\": \\"https://github.com/customUrl/docs/lorem.md\\",
|
||||||
|
@ -294,6 +330,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/rootAbsoluteSlug\\",
|
\\"slug\\": \\"/rootAbsoluteSlug\\",
|
||||||
\\"permalink\\": \\"/docs/rootAbsoluteSlug\\",
|
\\"permalink\\": \\"/docs/rootAbsoluteSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"/rootAbsoluteSlug\\"
|
\\"slug\\": \\"/rootAbsoluteSlug\\"
|
||||||
|
@ -309,6 +346,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/rootRelativeSlug\\",
|
\\"slug\\": \\"/rootRelativeSlug\\",
|
||||||
\\"permalink\\": \\"/docs/rootRelativeSlug\\",
|
\\"permalink\\": \\"/docs/rootRelativeSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"rootRelativeSlug\\"
|
\\"slug\\": \\"rootRelativeSlug\\"
|
||||||
|
@ -324,6 +362,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/hey/rootResolvedSlug\\",
|
\\"slug\\": \\"/hey/rootResolvedSlug\\",
|
||||||
\\"permalink\\": \\"/docs/hey/rootResolvedSlug\\",
|
\\"permalink\\": \\"/docs/hey/rootResolvedSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"./hey/ho/../rootResolvedSlug\\"
|
\\"slug\\": \\"./hey/ho/../rootResolvedSlug\\"
|
||||||
|
@ -339,6 +378,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/rootTryToEscapeSlug\\",
|
\\"slug\\": \\"/rootTryToEscapeSlug\\",
|
||||||
\\"permalink\\": \\"/docs/rootTryToEscapeSlug\\",
|
\\"permalink\\": \\"/docs/rootTryToEscapeSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"../../../../../../../../rootTryToEscapeSlug\\"
|
\\"slug\\": \\"../../../../../../../../rootTryToEscapeSlug\\"
|
||||||
|
@ -354,6 +394,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\"slugs\\",
|
\\"sourceDirName\\": \\"slugs\\",
|
||||||
\\"slug\\": \\"/absoluteSlug\\",
|
\\"slug\\": \\"/absoluteSlug\\",
|
||||||
\\"permalink\\": \\"/docs/absoluteSlug\\",
|
\\"permalink\\": \\"/docs/absoluteSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"/absoluteSlug\\"
|
\\"slug\\": \\"/absoluteSlug\\"
|
||||||
|
@ -369,6 +410,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\"slugs\\",
|
\\"sourceDirName\\": \\"slugs\\",
|
||||||
\\"slug\\": \\"/slugs/relativeSlug\\",
|
\\"slug\\": \\"/slugs/relativeSlug\\",
|
||||||
\\"permalink\\": \\"/docs/slugs/relativeSlug\\",
|
\\"permalink\\": \\"/docs/slugs/relativeSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"relativeSlug\\"
|
\\"slug\\": \\"relativeSlug\\"
|
||||||
|
@ -384,6 +426,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\"slugs\\",
|
\\"sourceDirName\\": \\"slugs\\",
|
||||||
\\"slug\\": \\"/slugs/hey/resolvedSlug\\",
|
\\"slug\\": \\"/slugs/hey/resolvedSlug\\",
|
||||||
\\"permalink\\": \\"/docs/slugs/hey/resolvedSlug\\",
|
\\"permalink\\": \\"/docs/slugs/hey/resolvedSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"./hey/ho/../resolvedSlug\\"
|
\\"slug\\": \\"./hey/ho/../resolvedSlug\\"
|
||||||
|
@ -399,11 +442,74 @@ Object {
|
||||||
\\"sourceDirName\\": \\"slugs\\",
|
\\"sourceDirName\\": \\"slugs\\",
|
||||||
\\"slug\\": \\"/tryToEscapeSlug\\",
|
\\"slug\\": \\"/tryToEscapeSlug\\",
|
||||||
\\"permalink\\": \\"/docs/tryToEscapeSlug\\",
|
\\"permalink\\": \\"/docs/tryToEscapeSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"../../../../../../../../tryToEscapeSlug\\"
|
\\"slug\\": \\"../../../../../../../../tryToEscapeSlug\\"
|
||||||
}
|
}
|
||||||
}",
|
}",
|
||||||
|
"tag-docs-tags-tag-1-b3f.json": "{
|
||||||
|
\\"name\\": \\"tag 1\\",
|
||||||
|
\\"permalink\\": \\"/docs/tags/tag-1\\",
|
||||||
|
\\"docs\\": [
|
||||||
|
{
|
||||||
|
\\"id\\": \\"foo/baz\\",
|
||||||
|
\\"title\\": \\"baz\\",
|
||||||
|
\\"description\\": \\"Images\\",
|
||||||
|
\\"permalink\\": \\"/docs/foo/bazSlug.html\\"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"id\\": \\"hello\\",
|
||||||
|
\\"title\\": \\"Hello, World !\\",
|
||||||
|
\\"description\\": \\"Hi, Endilie here :)\\",
|
||||||
|
\\"permalink\\": \\"/docs/\\"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"allTagsPath\\": \\"/docs/tags\\"
|
||||||
|
}",
|
||||||
|
"tag-docs-tags-tag-2-custom-permalink-825.json": "{
|
||||||
|
\\"name\\": \\"tag 2\\",
|
||||||
|
\\"permalink\\": \\"/docs/tags/tag2-custom-permalink\\",
|
||||||
|
\\"docs\\": [
|
||||||
|
{
|
||||||
|
\\"id\\": \\"foo/baz\\",
|
||||||
|
\\"title\\": \\"baz\\",
|
||||||
|
\\"description\\": \\"Images\\",
|
||||||
|
\\"permalink\\": \\"/docs/foo/bazSlug.html\\"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"allTagsPath\\": \\"/docs/tags\\"
|
||||||
|
}",
|
||||||
|
"tag-docs-tags-tag-3-ab5.json": "{
|
||||||
|
\\"name\\": \\"tag 3\\",
|
||||||
|
\\"permalink\\": \\"/docs/tags/tag-3\\",
|
||||||
|
\\"docs\\": [
|
||||||
|
{
|
||||||
|
\\"id\\": \\"hello\\",
|
||||||
|
\\"title\\": \\"Hello, World !\\",
|
||||||
|
\\"description\\": \\"Hi, Endilie here :)\\",
|
||||||
|
\\"permalink\\": \\"/docs/\\"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"allTagsPath\\": \\"/docs/tags\\"
|
||||||
|
}",
|
||||||
|
"tags-list-current-prop-15a.json": "[
|
||||||
|
{
|
||||||
|
\\"name\\": \\"tag 1\\",
|
||||||
|
\\"permalink\\": \\"/docs/tags/tag-1\\",
|
||||||
|
\\"count\\": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"name\\": \\"tag 2\\",
|
||||||
|
\\"permalink\\": \\"/docs/tags/tag2-custom-permalink\\",
|
||||||
|
\\"count\\": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"name\\": \\"tag 3\\",
|
||||||
|
\\"permalink\\": \\"/docs/tags/tag-3\\",
|
||||||
|
\\"count\\": 1
|
||||||
|
}
|
||||||
|
]",
|
||||||
"version-current-metadata-prop-751.json": "{
|
"version-current-metadata-prop-751.json": "{
|
||||||
\\"pluginId\\": \\"default\\",
|
\\"pluginId\\": \\"default\\",
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
|
@ -560,6 +666,38 @@ Object {
|
||||||
|
|
||||||
exports[`simple website content: route config 1`] = `
|
exports[`simple website content: route config 1`] = `
|
||||||
Array [
|
Array [
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocTagsListPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"tags": "~docs/tags-list-current-prop-15a.json",
|
||||||
|
},
|
||||||
|
"path": "/docs/tags",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocTagDocListPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"tag": "~docs/tag-docs-tags-tag-1-b3f.json",
|
||||||
|
},
|
||||||
|
"path": "/docs/tags/tag-1",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocTagDocListPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"tag": "~docs/tag-docs-tags-tag-3-ab5.json",
|
||||||
|
},
|
||||||
|
"path": "/docs/tags/tag-3",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocTagDocListPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"tag": "~docs/tag-docs-tags-tag-2-custom-permalink-825.json",
|
||||||
|
},
|
||||||
|
"path": "/docs/tags/tag2-custom-permalink",
|
||||||
|
},
|
||||||
Object {
|
Object {
|
||||||
"component": "@theme/DocPage",
|
"component": "@theme/DocPage",
|
||||||
"exact": false,
|
"exact": false,
|
||||||
|
@ -857,6 +995,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/team\\",
|
\\"slug\\": \\"/team\\",
|
||||||
\\"permalink\\": \\"/community/team\\",
|
\\"permalink\\": \\"/community/team\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"1.0.0\\",
|
\\"version\\": \\"1.0.0\\",
|
||||||
\\"frontMatter\\": {},
|
\\"frontMatter\\": {},
|
||||||
\\"sidebar\\": \\"version-1.0.0/community\\"
|
\\"sidebar\\": \\"version-1.0.0/community\\"
|
||||||
|
@ -871,12 +1010,15 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/team\\",
|
\\"slug\\": \\"/team\\",
|
||||||
\\"permalink\\": \\"/community/next/team\\",
|
\\"permalink\\": \\"/community/next/team\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"title\\": \\"Team title translated\\"
|
\\"title\\": \\"Team title translated\\"
|
||||||
},
|
},
|
||||||
\\"sidebar\\": \\"community\\"
|
\\"sidebar\\": \\"community\\"
|
||||||
}",
|
}",
|
||||||
|
"tags-list-1-0-0-prop-483.json": "[]",
|
||||||
|
"tags-list-current-prop-15a.json": "[]",
|
||||||
"version-1-0-0-metadata-prop-608.json": "{
|
"version-1-0-0-metadata-prop-608.json": "{
|
||||||
\\"pluginId\\": \\"community\\",
|
\\"pluginId\\": \\"community\\",
|
||||||
\\"version\\": \\"1.0.0\\",
|
\\"version\\": \\"1.0.0\\",
|
||||||
|
@ -954,6 +1096,22 @@ Object {
|
||||||
|
|
||||||
exports[`versioned website (community) content: route config 1`] = `
|
exports[`versioned website (community) content: route config 1`] = `
|
||||||
Array [
|
Array [
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocTagsListPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"tags": "~docs/tags-list-current-prop-15a.json",
|
||||||
|
},
|
||||||
|
"path": "/community/next/tags",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocTagsListPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"tags": "~docs/tags-list-1-0-0-prop-483.json",
|
||||||
|
},
|
||||||
|
"path": "/community/tags",
|
||||||
|
},
|
||||||
Object {
|
Object {
|
||||||
"component": "@theme/DocPage",
|
"component": "@theme/DocPage",
|
||||||
"exact": false,
|
"exact": false,
|
||||||
|
@ -1106,9 +1264,31 @@ Object {
|
||||||
\\"sourceDirName\\": \\"foo\\",
|
\\"sourceDirName\\": \\"foo\\",
|
||||||
\\"slug\\": \\"/foo/barSlug\\",
|
\\"slug\\": \\"/foo/barSlug\\",
|
||||||
\\"permalink\\": \\"/docs/next/foo/barSlug\\",
|
\\"permalink\\": \\"/docs/next/foo/barSlug\\",
|
||||||
|
\\"tags\\": [
|
||||||
|
{
|
||||||
|
\\"label\\": \\"barTag 1\\",
|
||||||
|
\\"permalink\\": \\"/docs/next/tags/bar-tag-1\\"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"label\\": \\"barTag-2\\",
|
||||||
|
\\"permalink\\": \\"/docs/next/tags/bar-tag-2\\"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"label\\": \\"barTag 3\\",
|
||||||
|
\\"permalink\\": \\"/docs/next/tags/barTag-3-permalink\\"
|
||||||
|
}
|
||||||
|
],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"barSlug\\"
|
\\"slug\\": \\"barSlug\\",
|
||||||
|
\\"tags\\": [
|
||||||
|
\\"barTag 1\\",
|
||||||
|
\\"barTag-2\\",
|
||||||
|
{
|
||||||
|
\\"label\\": \\"barTag 3\\",
|
||||||
|
\\"permalink\\": \\"barTag-3-permalink\\"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
\\"sidebar\\": \\"docs\\",
|
\\"sidebar\\": \\"docs\\",
|
||||||
\\"next\\": {
|
\\"next\\": {
|
||||||
|
@ -1126,6 +1306,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/\\",
|
\\"slug\\": \\"/\\",
|
||||||
\\"permalink\\": \\"/docs/next/\\",
|
\\"permalink\\": \\"/docs/next/\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {},
|
\\"frontMatter\\": {},
|
||||||
\\"sidebar\\": \\"docs\\",
|
\\"sidebar\\": \\"docs\\",
|
||||||
|
@ -1144,6 +1325,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\"slugs\\",
|
\\"sourceDirName\\": \\"slugs\\",
|
||||||
\\"slug\\": \\"/absoluteSlug\\",
|
\\"slug\\": \\"/absoluteSlug\\",
|
||||||
\\"permalink\\": \\"/docs/next/absoluteSlug\\",
|
\\"permalink\\": \\"/docs/next/absoluteSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"/absoluteSlug\\"
|
\\"slug\\": \\"/absoluteSlug\\"
|
||||||
|
@ -1159,6 +1341,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\"slugs\\",
|
\\"sourceDirName\\": \\"slugs\\",
|
||||||
\\"slug\\": \\"/slugs/relativeSlug\\",
|
\\"slug\\": \\"/slugs/relativeSlug\\",
|
||||||
\\"permalink\\": \\"/docs/next/slugs/relativeSlug\\",
|
\\"permalink\\": \\"/docs/next/slugs/relativeSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"relativeSlug\\"
|
\\"slug\\": \\"relativeSlug\\"
|
||||||
|
@ -1174,6 +1357,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\"slugs\\",
|
\\"sourceDirName\\": \\"slugs\\",
|
||||||
\\"slug\\": \\"/slugs/hey/resolvedSlug\\",
|
\\"slug\\": \\"/slugs/hey/resolvedSlug\\",
|
||||||
\\"permalink\\": \\"/docs/next/slugs/hey/resolvedSlug\\",
|
\\"permalink\\": \\"/docs/next/slugs/hey/resolvedSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"./hey/ho/../resolvedSlug\\"
|
\\"slug\\": \\"./hey/ho/../resolvedSlug\\"
|
||||||
|
@ -1189,6 +1373,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\"slugs\\",
|
\\"sourceDirName\\": \\"slugs\\",
|
||||||
\\"slug\\": \\"/tryToEscapeSlug\\",
|
\\"slug\\": \\"/tryToEscapeSlug\\",
|
||||||
\\"permalink\\": \\"/docs/next/tryToEscapeSlug\\",
|
\\"permalink\\": \\"/docs/next/tryToEscapeSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"current\\",
|
\\"version\\": \\"current\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"../../../../../../../../tryToEscapeSlug\\"
|
\\"slug\\": \\"../../../../../../../../tryToEscapeSlug\\"
|
||||||
|
@ -1204,6 +1389,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/\\",
|
\\"slug\\": \\"/\\",
|
||||||
\\"permalink\\": \\"/docs/1.0.0/\\",
|
\\"permalink\\": \\"/docs/1.0.0/\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"1.0.0\\",
|
\\"version\\": \\"1.0.0\\",
|
||||||
\\"frontMatter\\": {},
|
\\"frontMatter\\": {},
|
||||||
\\"sidebar\\": \\"version-1.0.0/docs\\",
|
\\"sidebar\\": \\"version-1.0.0/docs\\",
|
||||||
|
@ -1222,6 +1408,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\"foo\\",
|
\\"sourceDirName\\": \\"foo\\",
|
||||||
\\"slug\\": \\"/foo/barSlug\\",
|
\\"slug\\": \\"/foo/barSlug\\",
|
||||||
\\"permalink\\": \\"/docs/1.0.0/foo/barSlug\\",
|
\\"permalink\\": \\"/docs/1.0.0/foo/barSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"1.0.0\\",
|
\\"version\\": \\"1.0.0\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"barSlug\\"
|
\\"slug\\": \\"barSlug\\"
|
||||||
|
@ -1242,6 +1429,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\"foo\\",
|
\\"sourceDirName\\": \\"foo\\",
|
||||||
\\"slug\\": \\"/foo/baz\\",
|
\\"slug\\": \\"/foo/baz\\",
|
||||||
\\"permalink\\": \\"/docs/1.0.0/foo/baz\\",
|
\\"permalink\\": \\"/docs/1.0.0/foo/baz\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"1.0.0\\",
|
\\"version\\": \\"1.0.0\\",
|
||||||
\\"frontMatter\\": {},
|
\\"frontMatter\\": {},
|
||||||
\\"sidebar\\": \\"version-1.0.0/docs\\",
|
\\"sidebar\\": \\"version-1.0.0/docs\\",
|
||||||
|
@ -1264,6 +1452,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\"foo\\",
|
\\"sourceDirName\\": \\"foo\\",
|
||||||
\\"slug\\": \\"/foo/bar\\",
|
\\"slug\\": \\"/foo/bar\\",
|
||||||
\\"permalink\\": \\"/docs/foo/bar\\",
|
\\"permalink\\": \\"/docs/foo/bar\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"1.0.1\\",
|
\\"version\\": \\"1.0.1\\",
|
||||||
\\"frontMatter\\": {},
|
\\"frontMatter\\": {},
|
||||||
\\"sidebar\\": \\"version-1.0.1/docs\\",
|
\\"sidebar\\": \\"version-1.0.1/docs\\",
|
||||||
|
@ -1282,6 +1471,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/\\",
|
\\"slug\\": \\"/\\",
|
||||||
\\"permalink\\": \\"/docs/\\",
|
\\"permalink\\": \\"/docs/\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"1.0.1\\",
|
\\"version\\": \\"1.0.1\\",
|
||||||
\\"frontMatter\\": {},
|
\\"frontMatter\\": {},
|
||||||
\\"sidebar\\": \\"version-1.0.1/docs\\",
|
\\"sidebar\\": \\"version-1.0.1/docs\\",
|
||||||
|
@ -1300,6 +1490,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/rootAbsoluteSlug\\",
|
\\"slug\\": \\"/rootAbsoluteSlug\\",
|
||||||
\\"permalink\\": \\"/docs/withSlugs/rootAbsoluteSlug\\",
|
\\"permalink\\": \\"/docs/withSlugs/rootAbsoluteSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"withSlugs\\",
|
\\"version\\": \\"withSlugs\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"/rootAbsoluteSlug\\"
|
\\"slug\\": \\"/rootAbsoluteSlug\\"
|
||||||
|
@ -1316,6 +1507,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/rootRelativeSlug\\",
|
\\"slug\\": \\"/rootRelativeSlug\\",
|
||||||
\\"permalink\\": \\"/docs/withSlugs/rootRelativeSlug\\",
|
\\"permalink\\": \\"/docs/withSlugs/rootRelativeSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"withSlugs\\",
|
\\"version\\": \\"withSlugs\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"rootRelativeSlug\\"
|
\\"slug\\": \\"rootRelativeSlug\\"
|
||||||
|
@ -1331,6 +1523,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/hey/rootResolvedSlug\\",
|
\\"slug\\": \\"/hey/rootResolvedSlug\\",
|
||||||
\\"permalink\\": \\"/docs/withSlugs/hey/rootResolvedSlug\\",
|
\\"permalink\\": \\"/docs/withSlugs/hey/rootResolvedSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"withSlugs\\",
|
\\"version\\": \\"withSlugs\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"./hey/ho/../rootResolvedSlug\\"
|
\\"slug\\": \\"./hey/ho/../rootResolvedSlug\\"
|
||||||
|
@ -1346,6 +1539,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\".\\",
|
\\"sourceDirName\\": \\".\\",
|
||||||
\\"slug\\": \\"/rootTryToEscapeSlug\\",
|
\\"slug\\": \\"/rootTryToEscapeSlug\\",
|
||||||
\\"permalink\\": \\"/docs/withSlugs/rootTryToEscapeSlug\\",
|
\\"permalink\\": \\"/docs/withSlugs/rootTryToEscapeSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"withSlugs\\",
|
\\"version\\": \\"withSlugs\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"../../../../../../../../rootTryToEscapeSlug\\"
|
\\"slug\\": \\"../../../../../../../../rootTryToEscapeSlug\\"
|
||||||
|
@ -1361,6 +1555,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\"slugs\\",
|
\\"sourceDirName\\": \\"slugs\\",
|
||||||
\\"slug\\": \\"/absoluteSlug\\",
|
\\"slug\\": \\"/absoluteSlug\\",
|
||||||
\\"permalink\\": \\"/docs/withSlugs/absoluteSlug\\",
|
\\"permalink\\": \\"/docs/withSlugs/absoluteSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"withSlugs\\",
|
\\"version\\": \\"withSlugs\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"/absoluteSlug\\"
|
\\"slug\\": \\"/absoluteSlug\\"
|
||||||
|
@ -1376,6 +1571,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\"slugs\\",
|
\\"sourceDirName\\": \\"slugs\\",
|
||||||
\\"slug\\": \\"/slugs/relativeSlug\\",
|
\\"slug\\": \\"/slugs/relativeSlug\\",
|
||||||
\\"permalink\\": \\"/docs/withSlugs/slugs/relativeSlug\\",
|
\\"permalink\\": \\"/docs/withSlugs/slugs/relativeSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"withSlugs\\",
|
\\"version\\": \\"withSlugs\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"relativeSlug\\"
|
\\"slug\\": \\"relativeSlug\\"
|
||||||
|
@ -1391,6 +1587,7 @@ Object {
|
||||||
\\"sourceDirName\\": \\"slugs\\",
|
\\"sourceDirName\\": \\"slugs\\",
|
||||||
\\"slug\\": \\"/slugs/hey/resolvedSlug\\",
|
\\"slug\\": \\"/slugs/hey/resolvedSlug\\",
|
||||||
\\"permalink\\": \\"/docs/withSlugs/slugs/hey/resolvedSlug\\",
|
\\"permalink\\": \\"/docs/withSlugs/slugs/hey/resolvedSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"withSlugs\\",
|
\\"version\\": \\"withSlugs\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"./hey/ho/../resolvedSlug\\"
|
\\"slug\\": \\"./hey/ho/../resolvedSlug\\"
|
||||||
|
@ -1406,11 +1603,71 @@ Object {
|
||||||
\\"sourceDirName\\": \\"slugs\\",
|
\\"sourceDirName\\": \\"slugs\\",
|
||||||
\\"slug\\": \\"/tryToEscapeSlug\\",
|
\\"slug\\": \\"/tryToEscapeSlug\\",
|
||||||
\\"permalink\\": \\"/docs/withSlugs/tryToEscapeSlug\\",
|
\\"permalink\\": \\"/docs/withSlugs/tryToEscapeSlug\\",
|
||||||
|
\\"tags\\": [],
|
||||||
\\"version\\": \\"withSlugs\\",
|
\\"version\\": \\"withSlugs\\",
|
||||||
\\"frontMatter\\": {
|
\\"frontMatter\\": {
|
||||||
\\"slug\\": \\"../../../../../../../../tryToEscapeSlug\\"
|
\\"slug\\": \\"../../../../../../../../tryToEscapeSlug\\"
|
||||||
}
|
}
|
||||||
}",
|
}",
|
||||||
|
"tag-docs-next-tags-bar-tag-1-a8f.json": "{
|
||||||
|
\\"name\\": \\"barTag 1\\",
|
||||||
|
\\"permalink\\": \\"/docs/next/tags/bar-tag-1\\",
|
||||||
|
\\"docs\\": [
|
||||||
|
{
|
||||||
|
\\"id\\": \\"foo/bar\\",
|
||||||
|
\\"title\\": \\"bar\\",
|
||||||
|
\\"description\\": \\"This is next version of bar.\\",
|
||||||
|
\\"permalink\\": \\"/docs/next/foo/barSlug\\"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"allTagsPath\\": \\"/docs/next/tags\\"
|
||||||
|
}",
|
||||||
|
"tag-docs-next-tags-bar-tag-2-216.json": "{
|
||||||
|
\\"name\\": \\"barTag-2\\",
|
||||||
|
\\"permalink\\": \\"/docs/next/tags/bar-tag-2\\",
|
||||||
|
\\"docs\\": [
|
||||||
|
{
|
||||||
|
\\"id\\": \\"foo/bar\\",
|
||||||
|
\\"title\\": \\"bar\\",
|
||||||
|
\\"description\\": \\"This is next version of bar.\\",
|
||||||
|
\\"permalink\\": \\"/docs/next/foo/barSlug\\"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"allTagsPath\\": \\"/docs/next/tags\\"
|
||||||
|
}",
|
||||||
|
"tag-docs-next-tags-bar-tag-3-permalink-94a.json": "{
|
||||||
|
\\"name\\": \\"barTag 3\\",
|
||||||
|
\\"permalink\\": \\"/docs/next/tags/barTag-3-permalink\\",
|
||||||
|
\\"docs\\": [
|
||||||
|
{
|
||||||
|
\\"id\\": \\"foo/bar\\",
|
||||||
|
\\"title\\": \\"bar\\",
|
||||||
|
\\"description\\": \\"This is next version of bar.\\",
|
||||||
|
\\"permalink\\": \\"/docs/next/foo/barSlug\\"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
\\"allTagsPath\\": \\"/docs/next/tags\\"
|
||||||
|
}",
|
||||||
|
"tags-list-1-0-0-prop-483.json": "[]",
|
||||||
|
"tags-list-1-0-1-prop-c39.json": "[]",
|
||||||
|
"tags-list-current-prop-15a.json": "[
|
||||||
|
{
|
||||||
|
\\"name\\": \\"barTag 1\\",
|
||||||
|
\\"permalink\\": \\"/docs/next/tags/bar-tag-1\\",
|
||||||
|
\\"count\\": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"name\\": \\"barTag-2\\",
|
||||||
|
\\"permalink\\": \\"/docs/next/tags/bar-tag-2\\",
|
||||||
|
\\"count\\": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
\\"name\\": \\"barTag 3\\",
|
||||||
|
\\"permalink\\": \\"/docs/next/tags/barTag-3-permalink\\",
|
||||||
|
\\"count\\": 1
|
||||||
|
}
|
||||||
|
]",
|
||||||
|
"tags-list-with-slugs-prop-1ca.json": "[]",
|
||||||
"version-1-0-0-metadata-prop-608.json": "{
|
"version-1-0-0-metadata-prop-608.json": "{
|
||||||
\\"pluginId\\": \\"default\\",
|
\\"pluginId\\": \\"default\\",
|
||||||
\\"version\\": \\"1.0.0\\",
|
\\"version\\": \\"1.0.0\\",
|
||||||
|
@ -1699,6 +1956,62 @@ Object {
|
||||||
|
|
||||||
exports[`versioned website content: route config 1`] = `
|
exports[`versioned website content: route config 1`] = `
|
||||||
Array [
|
Array [
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocTagsListPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"tags": "~docs/tags-list-1-0-0-prop-483.json",
|
||||||
|
},
|
||||||
|
"path": "/docs/1.0.0/tags",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocTagsListPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"tags": "~docs/tags-list-current-prop-15a.json",
|
||||||
|
},
|
||||||
|
"path": "/docs/next/tags",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocTagDocListPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"tag": "~docs/tag-docs-next-tags-bar-tag-1-a8f.json",
|
||||||
|
},
|
||||||
|
"path": "/docs/next/tags/bar-tag-1",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocTagDocListPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"tag": "~docs/tag-docs-next-tags-bar-tag-2-216.json",
|
||||||
|
},
|
||||||
|
"path": "/docs/next/tags/bar-tag-2",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocTagDocListPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"tag": "~docs/tag-docs-next-tags-bar-tag-3-permalink-94a.json",
|
||||||
|
},
|
||||||
|
"path": "/docs/next/tags/barTag-3-permalink",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocTagsListPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"tags": "~docs/tags-list-1-0-1-prop-c39.json",
|
||||||
|
},
|
||||||
|
"path": "/docs/tags",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocTagsListPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"tags": "~docs/tags-list-with-slugs-prop-1ca.json",
|
||||||
|
},
|
||||||
|
"path": "/docs/withSlugs/tags",
|
||||||
|
},
|
||||||
Object {
|
Object {
|
||||||
"component": "@theme/DocPage",
|
"component": "@theme/DocPage",
|
||||||
"exact": false,
|
"exact": false,
|
||||||
|
|
|
@ -187,6 +187,7 @@ describe('simple site', () => {
|
||||||
id: 'bar',
|
id: 'bar',
|
||||||
title: 'Bar',
|
title: 'Bar',
|
||||||
},
|
},
|
||||||
|
tags: [],
|
||||||
});
|
});
|
||||||
await defaultTestUtils.testMeta(path.join('hello.md'), {
|
await defaultTestUtils.testMeta(path.join('hello.md'), {
|
||||||
version: 'current',
|
version: 'current',
|
||||||
|
@ -202,7 +203,18 @@ describe('simple site', () => {
|
||||||
id: 'hello',
|
id: 'hello',
|
||||||
title: 'Hello, World !',
|
title: 'Hello, World !',
|
||||||
sidebar_label: 'Hello sidebar_label',
|
sidebar_label: 'Hello sidebar_label',
|
||||||
|
tags: ['tag-1', 'tag 3'],
|
||||||
},
|
},
|
||||||
|
tags: [
|
||||||
|
{
|
||||||
|
label: 'tag-1',
|
||||||
|
permalink: '/docs/tags/tag-1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'tag 3',
|
||||||
|
permalink: '/docs/tags/tag-3',
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -232,7 +244,18 @@ describe('simple site', () => {
|
||||||
id: 'hello',
|
id: 'hello',
|
||||||
title: 'Hello, World !',
|
title: 'Hello, World !',
|
||||||
sidebar_label: 'Hello sidebar_label',
|
sidebar_label: 'Hello sidebar_label',
|
||||||
|
tags: ['tag-1', 'tag 3'],
|
||||||
},
|
},
|
||||||
|
tags: [
|
||||||
|
{
|
||||||
|
label: 'tag-1',
|
||||||
|
permalink: '/docs/tags/tag-1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'tag 3',
|
||||||
|
permalink: '/docs/tags/tag-3',
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -263,6 +286,7 @@ describe('simple site', () => {
|
||||||
id: 'bar',
|
id: 'bar',
|
||||||
title: 'Bar',
|
title: 'Bar',
|
||||||
},
|
},
|
||||||
|
tags: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -297,7 +321,22 @@ describe('simple site', () => {
|
||||||
slug: 'bazSlug.html',
|
slug: 'bazSlug.html',
|
||||||
title: 'baz',
|
title: 'baz',
|
||||||
pagination_label: 'baz pagination_label',
|
pagination_label: 'baz pagination_label',
|
||||||
|
tags: [
|
||||||
|
'tag 1',
|
||||||
|
'tag-1',
|
||||||
|
{label: 'tag 2', permalink: 'tag2-custom-permalink'},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
tags: [
|
||||||
|
{
|
||||||
|
label: 'tag 1',
|
||||||
|
permalink: '/docs/tags/tag-1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'tag 2',
|
||||||
|
permalink: '/docs/tags/tag2-custom-permalink',
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -319,6 +358,7 @@ describe('simple site', () => {
|
||||||
custom_edit_url: 'https://github.com/customUrl/docs/lorem.md',
|
custom_edit_url: 'https://github.com/customUrl/docs/lorem.md',
|
||||||
unrelated_frontmatter: "won't be part of metadata",
|
unrelated_frontmatter: "won't be part of metadata",
|
||||||
},
|
},
|
||||||
|
tags: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -356,7 +396,22 @@ describe('simple site', () => {
|
||||||
slug: 'bazSlug.html',
|
slug: 'bazSlug.html',
|
||||||
title: 'baz',
|
title: 'baz',
|
||||||
pagination_label: 'baz pagination_label',
|
pagination_label: 'baz pagination_label',
|
||||||
|
tags: [
|
||||||
|
'tag 1',
|
||||||
|
'tag-1',
|
||||||
|
{label: 'tag 2', permalink: 'tag2-custom-permalink'},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
tags: [
|
||||||
|
{
|
||||||
|
label: 'tag 1',
|
||||||
|
permalink: '/docs/tags/tag-1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'tag 2',
|
||||||
|
permalink: '/docs/tags/tag2-custom-permalink',
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(editUrlFunction).toHaveBeenCalledTimes(1);
|
expect(editUrlFunction).toHaveBeenCalledTimes(1);
|
||||||
|
@ -402,6 +457,7 @@ describe('simple site', () => {
|
||||||
lastUpdatedAt: 1539502055,
|
lastUpdatedAt: 1539502055,
|
||||||
formattedLastUpdatedAt: '10/14/2018',
|
formattedLastUpdatedAt: '10/14/2018',
|
||||||
lastUpdatedBy: 'Author',
|
lastUpdatedBy: 'Author',
|
||||||
|
tags: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -559,6 +615,7 @@ describe('versioned site', () => {
|
||||||
|
|
||||||
await currentVersionTestUtils.testMeta(path.join('foo', 'bar.md'), {
|
await currentVersionTestUtils.testMeta(path.join('foo', 'bar.md'), {
|
||||||
id: 'foo/bar',
|
id: 'foo/bar',
|
||||||
|
version: 'current',
|
||||||
unversionedId: 'foo/bar',
|
unversionedId: 'foo/bar',
|
||||||
sourceDirName: 'foo',
|
sourceDirName: 'foo',
|
||||||
isDocsHomePage: false,
|
isDocsHomePage: false,
|
||||||
|
@ -566,11 +623,35 @@ describe('versioned site', () => {
|
||||||
slug: '/foo/barSlug',
|
slug: '/foo/barSlug',
|
||||||
title: 'bar',
|
title: 'bar',
|
||||||
description: 'This is next version of bar.',
|
description: 'This is next version of bar.',
|
||||||
frontMatter: {slug: 'barSlug'},
|
frontMatter: {
|
||||||
version: 'current',
|
slug: 'barSlug',
|
||||||
|
tags: [
|
||||||
|
'barTag 1',
|
||||||
|
'barTag-2',
|
||||||
|
{
|
||||||
|
label: 'barTag 3',
|
||||||
|
permalink: 'barTag-3-permalink',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
tags: [
|
||||||
|
{
|
||||||
|
label: 'barTag 1',
|
||||||
|
permalink: '/docs/next/tags/bar-tag-1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'barTag-2',
|
||||||
|
permalink: '/docs/next/tags/bar-tag-2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'barTag 3',
|
||||||
|
permalink: '/docs/next/tags/barTag-3-permalink',
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
await currentVersionTestUtils.testMeta(path.join('hello.md'), {
|
await currentVersionTestUtils.testMeta(path.join('hello.md'), {
|
||||||
id: 'hello',
|
id: 'hello',
|
||||||
|
version: 'current',
|
||||||
unversionedId: 'hello',
|
unversionedId: 'hello',
|
||||||
sourceDirName: '.',
|
sourceDirName: '.',
|
||||||
isDocsHomePage: false,
|
isDocsHomePage: false,
|
||||||
|
@ -579,7 +660,7 @@ describe('versioned site', () => {
|
||||||
title: 'hello',
|
title: 'hello',
|
||||||
description: 'Hello next !',
|
description: 'Hello next !',
|
||||||
frontMatter: {},
|
frontMatter: {},
|
||||||
version: 'current',
|
tags: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -597,6 +678,7 @@ describe('versioned site', () => {
|
||||||
description: 'Bar 1.0.0 !',
|
description: 'Bar 1.0.0 !',
|
||||||
frontMatter: {slug: 'barSlug'},
|
frontMatter: {slug: 'barSlug'},
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
|
tags: [],
|
||||||
});
|
});
|
||||||
await version100TestUtils.testMeta(path.join('hello.md'), {
|
await version100TestUtils.testMeta(path.join('hello.md'), {
|
||||||
id: 'version-1.0.0/hello',
|
id: 'version-1.0.0/hello',
|
||||||
|
@ -611,6 +693,7 @@ describe('versioned site', () => {
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
source:
|
source:
|
||||||
'@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
'@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
||||||
|
tags: [],
|
||||||
});
|
});
|
||||||
await version101TestUtils.testMeta(path.join('foo', 'bar.md'), {
|
await version101TestUtils.testMeta(path.join('foo', 'bar.md'), {
|
||||||
id: 'version-1.0.1/foo/bar',
|
id: 'version-1.0.1/foo/bar',
|
||||||
|
@ -623,6 +706,7 @@ describe('versioned site', () => {
|
||||||
description: 'Bar 1.0.1 !',
|
description: 'Bar 1.0.1 !',
|
||||||
version: '1.0.1',
|
version: '1.0.1',
|
||||||
frontMatter: {},
|
frontMatter: {},
|
||||||
|
tags: [],
|
||||||
});
|
});
|
||||||
await version101TestUtils.testMeta(path.join('hello.md'), {
|
await version101TestUtils.testMeta(path.join('hello.md'), {
|
||||||
id: 'version-1.0.1/hello',
|
id: 'version-1.0.1/hello',
|
||||||
|
@ -635,6 +719,7 @@ describe('versioned site', () => {
|
||||||
description: 'Hello 1.0.1 !',
|
description: 'Hello 1.0.1 !',
|
||||||
version: '1.0.1',
|
version: '1.0.1',
|
||||||
frontMatter: {},
|
frontMatter: {},
|
||||||
|
tags: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -729,6 +814,7 @@ describe('versioned site', () => {
|
||||||
source:
|
source:
|
||||||
'@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
'@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
||||||
editUrl: hardcodedEditUrl,
|
editUrl: hardcodedEditUrl,
|
||||||
|
tags: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(editUrlFunction).toHaveBeenCalledTimes(1);
|
expect(editUrlFunction).toHaveBeenCalledTimes(1);
|
||||||
|
@ -771,6 +857,7 @@ describe('versioned site', () => {
|
||||||
'@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
'@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
||||||
editUrl:
|
editUrl:
|
||||||
'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.0/hello.md',
|
'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.0/hello.md',
|
||||||
|
tags: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -804,6 +891,7 @@ describe('versioned site', () => {
|
||||||
'@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
'@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
||||||
editUrl:
|
editUrl:
|
||||||
'https://github.com/facebook/docusaurus/edit/main/website/docs/hello.md',
|
'https://github.com/facebook/docusaurus/edit/main/website/docs/hello.md',
|
||||||
|
tags: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -838,6 +926,7 @@ describe('versioned site', () => {
|
||||||
'@site/i18n/fr/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
'@site/i18n/fr/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
||||||
editUrl:
|
editUrl:
|
||||||
'https://github.com/facebook/docusaurus/edit/main/website/i18n/fr/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
'https://github.com/facebook/docusaurus/edit/main/website/i18n/fr/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
||||||
|
tags: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -873,6 +962,7 @@ describe('versioned site', () => {
|
||||||
'@site/i18n/fr/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
'@site/i18n/fr/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
||||||
editUrl:
|
editUrl:
|
||||||
'https://github.com/facebook/docusaurus/edit/main/website/i18n/fr/docusaurus-plugin-content-docs/current/hello.md',
|
'https://github.com/facebook/docusaurus/edit/main/website/i18n/fr/docusaurus-plugin-content-docs/current/hello.md',
|
||||||
|
tags: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -60,6 +60,7 @@ const defaultDocMetadata: Partial<DocMetadata> = {
|
||||||
lastUpdatedAt: undefined,
|
lastUpdatedAt: undefined,
|
||||||
lastUpdatedBy: undefined,
|
lastUpdatedBy: undefined,
|
||||||
formattedLastUpdatedAt: undefined,
|
formattedLastUpdatedAt: undefined,
|
||||||
|
tags: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const createFakeActions = (contentDir: string) => {
|
const createFakeActions = (contentDir: string) => {
|
||||||
|
@ -364,7 +365,23 @@ describe('simple website', () => {
|
||||||
title: 'baz',
|
title: 'baz',
|
||||||
slug: 'bazSlug.html',
|
slug: 'bazSlug.html',
|
||||||
pagination_label: 'baz pagination_label',
|
pagination_label: 'baz pagination_label',
|
||||||
|
tags: [
|
||||||
|
'tag 1',
|
||||||
|
'tag-1', // This one will be de-duplicated as it would lead to the same permalink as the first
|
||||||
|
{label: 'tag 2', permalink: 'tag2-custom-permalink'},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
tags: [
|
||||||
|
{
|
||||||
|
label: 'tag 1',
|
||||||
|
permalink: '/docs/tags/tag-1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'tag 2',
|
||||||
|
permalink: '/docs/tags/tag2-custom-permalink',
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(findDocById(currentVersion, 'hello')).toEqual({
|
expect(findDocById(currentVersion, 'hello')).toEqual({
|
||||||
|
@ -392,7 +409,18 @@ describe('simple website', () => {
|
||||||
id: 'hello',
|
id: 'hello',
|
||||||
title: 'Hello, World !',
|
title: 'Hello, World !',
|
||||||
sidebar_label: 'Hello sidebar_label',
|
sidebar_label: 'Hello sidebar_label',
|
||||||
|
tags: ['tag-1', 'tag 3'],
|
||||||
},
|
},
|
||||||
|
tags: [
|
||||||
|
{
|
||||||
|
label: 'tag-1',
|
||||||
|
permalink: '/docs/tags/tag-1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'tag 3',
|
||||||
|
permalink: '/docs/tags/tag-3',
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(getDocById(currentVersion, 'foo/bar')).toEqual({
|
expect(getDocById(currentVersion, 'foo/bar')).toEqual({
|
||||||
|
@ -579,6 +607,11 @@ describe('versioned website', () => {
|
||||||
description: 'This is next version of bar.',
|
description: 'This is next version of bar.',
|
||||||
frontMatter: {
|
frontMatter: {
|
||||||
slug: 'barSlug',
|
slug: 'barSlug',
|
||||||
|
tags: [
|
||||||
|
'barTag 1',
|
||||||
|
'barTag-2',
|
||||||
|
{label: 'barTag 3', permalink: 'barTag-3-permalink'},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
version: 'current',
|
version: 'current',
|
||||||
sidebar: 'docs',
|
sidebar: 'docs',
|
||||||
|
@ -586,6 +619,11 @@ describe('versioned website', () => {
|
||||||
title: 'hello',
|
title: 'hello',
|
||||||
permalink: '/docs/next/',
|
permalink: '/docs/next/',
|
||||||
},
|
},
|
||||||
|
tags: [
|
||||||
|
{label: 'barTag 1', permalink: '/docs/next/tags/bar-tag-1'},
|
||||||
|
{label: 'barTag-2', permalink: '/docs/next/tags/bar-tag-2'},
|
||||||
|
{label: 'barTag 3', permalink: '/docs/next/tags/barTag-3-permalink'},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
expect(getDocById(currentVersion, 'hello')).toEqual({
|
expect(getDocById(currentVersion, 'hello')).toEqual({
|
||||||
...defaultDocMetadata,
|
...defaultDocMetadata,
|
||||||
|
|
|
@ -48,6 +48,8 @@ describe('normalizeDocsPluginOptions', () => {
|
||||||
numberPrefixParser: DefaultNumberPrefixParser,
|
numberPrefixParser: DefaultNumberPrefixParser,
|
||||||
docLayoutComponent: '@theme/DocPage',
|
docLayoutComponent: '@theme/DocPage',
|
||||||
docItemComponent: '@theme/DocItem',
|
docItemComponent: '@theme/DocItem',
|
||||||
|
docTagDocListComponent: '@theme/DocTagDocListPage',
|
||||||
|
docTagsListComponent: '@theme/DocTagsListPage',
|
||||||
remarkPlugins: [markdownPluginsObjectStub],
|
remarkPlugins: [markdownPluginsObjectStub],
|
||||||
rehypePlugins: [markdownPluginsFunctionStub],
|
rehypePlugins: [markdownPluginsFunctionStub],
|
||||||
beforeDefaultRehypePlugins: [],
|
beforeDefaultRehypePlugins: [],
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
* 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 {toTagDocListProp} from '../props';
|
||||||
|
|
||||||
|
describe('toTagDocListProp', () => {
|
||||||
|
type Params = Parameters<typeof toTagDocListProp>[0];
|
||||||
|
type Tag = Params['tag'];
|
||||||
|
type Doc = Params['docs'][number];
|
||||||
|
|
||||||
|
const allTagsPath = '/all/tags';
|
||||||
|
|
||||||
|
test('should work', () => {
|
||||||
|
const tag: Tag = {
|
||||||
|
name: 'tag1',
|
||||||
|
permalink: '/tag1',
|
||||||
|
docIds: ['id1', 'id3'],
|
||||||
|
};
|
||||||
|
|
||||||
|
const doc1: Doc = {
|
||||||
|
id: 'id1',
|
||||||
|
title: 'ZZZ 1',
|
||||||
|
description: 'Description 1',
|
||||||
|
permalink: '/doc1',
|
||||||
|
};
|
||||||
|
const doc2: Doc = {
|
||||||
|
id: 'id2',
|
||||||
|
title: 'XXX 2',
|
||||||
|
description: 'Description 2',
|
||||||
|
permalink: '/doc2',
|
||||||
|
};
|
||||||
|
const doc3: Doc = {
|
||||||
|
id: 'id3',
|
||||||
|
title: 'AAA 3',
|
||||||
|
description: 'Description 3',
|
||||||
|
permalink: '/doc3',
|
||||||
|
};
|
||||||
|
const doc4: Doc = {
|
||||||
|
id: 'id4',
|
||||||
|
title: 'UUU 4',
|
||||||
|
description: 'Description 4',
|
||||||
|
permalink: '/doc4',
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = toTagDocListProp({
|
||||||
|
allTagsPath,
|
||||||
|
tag,
|
||||||
|
docs: [doc1, doc2, doc3, doc4],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
allTagsPath,
|
||||||
|
name: tag.name,
|
||||||
|
permalink: tag.permalink,
|
||||||
|
docs: [doc3, doc1], // docs sorted by title, ignore "id5" absence
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -77,6 +77,7 @@ describe('simple site', () => {
|
||||||
isLast: true,
|
isLast: true,
|
||||||
routePriority: -1,
|
routePriority: -1,
|
||||||
sidebarFilePath: undefined,
|
sidebarFilePath: undefined,
|
||||||
|
tagsPath: '/docs/tags',
|
||||||
versionLabel: 'Next',
|
versionLabel: 'Next',
|
||||||
versionName: 'current',
|
versionName: 'current',
|
||||||
versionPath: '/docs',
|
versionPath: '/docs',
|
||||||
|
@ -111,6 +112,7 @@ describe('simple site', () => {
|
||||||
{
|
{
|
||||||
...vCurrent,
|
...vCurrent,
|
||||||
versionPath: '/myBaseUrl/docs',
|
versionPath: '/myBaseUrl/docs',
|
||||||
|
tagsPath: '/myBaseUrl/docs/tags',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@ -141,6 +143,7 @@ describe('simple site', () => {
|
||||||
versionLabel: 'current-label',
|
versionLabel: 'current-label',
|
||||||
routePriority: undefined,
|
routePriority: undefined,
|
||||||
sidebarFilePath: undefined,
|
sidebarFilePath: undefined,
|
||||||
|
tagsPath: '/myBaseUrl/docs/current-path/tags',
|
||||||
versionEditUrl: undefined,
|
versionEditUrl: undefined,
|
||||||
versionEditUrlLocalized: undefined,
|
versionEditUrlLocalized: undefined,
|
||||||
},
|
},
|
||||||
|
@ -232,6 +235,7 @@ describe('versioned site, pluginId=default', () => {
|
||||||
isLast: false,
|
isLast: false,
|
||||||
routePriority: undefined,
|
routePriority: undefined,
|
||||||
sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'),
|
sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'),
|
||||||
|
tagsPath: '/docs/next/tags',
|
||||||
versionLabel: 'Next',
|
versionLabel: 'Next',
|
||||||
versionName: 'current',
|
versionName: 'current',
|
||||||
versionPath: '/docs/next',
|
versionPath: '/docs/next',
|
||||||
|
@ -250,6 +254,7 @@ describe('versioned site, pluginId=default', () => {
|
||||||
versionedSiteDir,
|
versionedSiteDir,
|
||||||
'versioned_sidebars/version-1.0.1-sidebars.json',
|
'versioned_sidebars/version-1.0.1-sidebars.json',
|
||||||
),
|
),
|
||||||
|
tagsPath: '/docs/tags',
|
||||||
versionLabel: '1.0.1',
|
versionLabel: '1.0.1',
|
||||||
versionName: '1.0.1',
|
versionName: '1.0.1',
|
||||||
versionPath: '/docs',
|
versionPath: '/docs',
|
||||||
|
@ -268,6 +273,7 @@ describe('versioned site, pluginId=default', () => {
|
||||||
versionedSiteDir,
|
versionedSiteDir,
|
||||||
'versioned_sidebars/version-1.0.0-sidebars.json',
|
'versioned_sidebars/version-1.0.0-sidebars.json',
|
||||||
),
|
),
|
||||||
|
tagsPath: '/docs/1.0.0/tags',
|
||||||
versionLabel: '1.0.0',
|
versionLabel: '1.0.0',
|
||||||
versionName: '1.0.0',
|
versionName: '1.0.0',
|
||||||
versionPath: '/docs/1.0.0',
|
versionPath: '/docs/1.0.0',
|
||||||
|
@ -289,6 +295,7 @@ describe('versioned site, pluginId=default', () => {
|
||||||
versionedSiteDir,
|
versionedSiteDir,
|
||||||
'versioned_sidebars/version-withSlugs-sidebars.json',
|
'versioned_sidebars/version-withSlugs-sidebars.json',
|
||||||
),
|
),
|
||||||
|
tagsPath: '/docs/withSlugs/tags',
|
||||||
versionLabel: 'withSlugs',
|
versionLabel: 'withSlugs',
|
||||||
versionName: 'withSlugs',
|
versionName: 'withSlugs',
|
||||||
versionPath: '/docs/withSlugs',
|
versionPath: '/docs/withSlugs',
|
||||||
|
@ -377,6 +384,7 @@ describe('versioned site, pluginId=default', () => {
|
||||||
expect(versionsMetadata).toEqual([
|
expect(versionsMetadata).toEqual([
|
||||||
{
|
{
|
||||||
...vCurrent,
|
...vCurrent,
|
||||||
|
tagsPath: '/docs/current-path/tags',
|
||||||
versionPath: '/docs/current-path',
|
versionPath: '/docs/current-path',
|
||||||
versionBanner: 'unmaintained',
|
versionBanner: 'unmaintained',
|
||||||
},
|
},
|
||||||
|
@ -384,6 +392,7 @@ describe('versioned site, pluginId=default', () => {
|
||||||
...v101,
|
...v101,
|
||||||
isLast: false,
|
isLast: false,
|
||||||
routePriority: undefined,
|
routePriority: undefined,
|
||||||
|
tagsPath: '/docs/1.0.1/tags',
|
||||||
versionPath: '/docs/1.0.1',
|
versionPath: '/docs/1.0.1',
|
||||||
versionBanner: 'unreleased',
|
versionBanner: 'unreleased',
|
||||||
},
|
},
|
||||||
|
@ -391,6 +400,7 @@ describe('versioned site, pluginId=default', () => {
|
||||||
...v100,
|
...v100,
|
||||||
isLast: true,
|
isLast: true,
|
||||||
routePriority: -1,
|
routePriority: -1,
|
||||||
|
tagsPath: '/docs/tags',
|
||||||
versionLabel: '1.0.0-label',
|
versionLabel: '1.0.0-label',
|
||||||
versionPath: '/docs',
|
versionPath: '/docs',
|
||||||
versionBanner: 'unreleased',
|
versionBanner: 'unreleased',
|
||||||
|
@ -528,6 +538,7 @@ describe('versioned site, pluginId=default', () => {
|
||||||
...vCurrent,
|
...vCurrent,
|
||||||
isLast: true,
|
isLast: true,
|
||||||
routePriority: -1,
|
routePriority: -1,
|
||||||
|
tagsPath: '/docs/tags',
|
||||||
versionPath: '/docs',
|
versionPath: '/docs',
|
||||||
versionBanner: 'none',
|
versionBanner: 'none',
|
||||||
},
|
},
|
||||||
|
@ -648,6 +659,7 @@ describe('versioned site, pluginId=community', () => {
|
||||||
isLast: false,
|
isLast: false,
|
||||||
routePriority: undefined,
|
routePriority: undefined,
|
||||||
sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'),
|
sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'),
|
||||||
|
tagsPath: '/communityBasePath/next/tags',
|
||||||
versionLabel: 'Next',
|
versionLabel: 'Next',
|
||||||
versionName: 'current',
|
versionName: 'current',
|
||||||
versionPath: '/communityBasePath/next',
|
versionPath: '/communityBasePath/next',
|
||||||
|
@ -669,6 +681,7 @@ describe('versioned site, pluginId=community', () => {
|
||||||
versionedSiteDir,
|
versionedSiteDir,
|
||||||
'community_versioned_sidebars/version-1.0.0-sidebars.json',
|
'community_versioned_sidebars/version-1.0.0-sidebars.json',
|
||||||
),
|
),
|
||||||
|
tagsPath: '/communityBasePath/tags',
|
||||||
versionLabel: '1.0.0',
|
versionLabel: '1.0.0',
|
||||||
versionName: '1.0.0',
|
versionName: '1.0.0',
|
||||||
versionPath: '/communityBasePath',
|
versionPath: '/communityBasePath',
|
||||||
|
@ -716,6 +729,7 @@ describe('versioned site, pluginId=community', () => {
|
||||||
...vCurrent,
|
...vCurrent,
|
||||||
isLast: true,
|
isLast: true,
|
||||||
routePriority: -1,
|
routePriority: -1,
|
||||||
|
tagsPath: '/communityBasePath/tags',
|
||||||
versionPath: '/communityBasePath',
|
versionPath: '/communityBasePath',
|
||||||
versionBanner: 'none',
|
versionBanner: 'none',
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
parseMarkdownString,
|
parseMarkdownString,
|
||||||
posixPath,
|
posixPath,
|
||||||
Globby,
|
Globby,
|
||||||
|
normalizeFrontMatterTags,
|
||||||
} from '@docusaurus/utils';
|
} from '@docusaurus/utils';
|
||||||
import {LoadContext} from '@docusaurus/types';
|
import {LoadContext} from '@docusaurus/types';
|
||||||
|
|
||||||
|
@ -252,6 +253,7 @@ function doProcessDocMetadata({
|
||||||
slug: docSlug,
|
slug: docSlug,
|
||||||
permalink,
|
permalink,
|
||||||
editUrl: customEditURL !== undefined ? customEditURL : getDocEditUrl(),
|
editUrl: customEditURL !== undefined ? customEditURL : getDocEditUrl(),
|
||||||
|
tags: normalizeFrontMatterTags(versionMetadata.tagsPath, frontMatter.tags),
|
||||||
version: versionMetadata.versionName,
|
version: versionMetadata.versionName,
|
||||||
lastUpdatedBy: lastUpdate.lastUpdatedBy,
|
lastUpdatedBy: lastUpdate.lastUpdatedBy,
|
||||||
lastUpdatedAt: lastUpdate.lastUpdatedAt,
|
lastUpdatedAt: lastUpdate.lastUpdatedAt,
|
||||||
|
|
|
@ -37,19 +37,22 @@ import {
|
||||||
LoadedVersion,
|
LoadedVersion,
|
||||||
DocFile,
|
DocFile,
|
||||||
DocsMarkdownOption,
|
DocsMarkdownOption,
|
||||||
|
VersionTag,
|
||||||
} from './types';
|
} from './types';
|
||||||
import {RuleSetRule} from 'webpack';
|
import {RuleSetRule} from 'webpack';
|
||||||
import {cliDocsVersionCommand} from './cli';
|
import {cliDocsVersionCommand} from './cli';
|
||||||
import {VERSIONS_JSON_FILE} from './constants';
|
import {VERSIONS_JSON_FILE} from './constants';
|
||||||
import {flatten, keyBy, compact, mapValues} from 'lodash';
|
import {flatten, keyBy, compact, mapValues} from 'lodash';
|
||||||
import {toGlobalDataVersion} from './globalData';
|
import {toGlobalDataVersion} from './globalData';
|
||||||
import {toVersionMetadataProp} from './props';
|
import {toTagDocListProp, toVersionMetadataProp} from './props';
|
||||||
import {
|
import {
|
||||||
translateLoadedContent,
|
translateLoadedContent,
|
||||||
getLoadedContentTranslationFiles,
|
getLoadedContentTranslationFiles,
|
||||||
} from './translations';
|
} from './translations';
|
||||||
import {CategoryMetadataFilenamePattern} from './sidebarItemsGenerator';
|
import {CategoryMetadataFilenamePattern} from './sidebarItemsGenerator';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
|
import {getVersionTags} from './tags';
|
||||||
|
import {PropTagsListPage} from '@docusaurus/plugin-content-docs-types';
|
||||||
|
|
||||||
export default function pluginContentDocs(
|
export default function pluginContentDocs(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
|
@ -314,9 +317,60 @@ export default function pluginContentDocs(
|
||||||
return routes.sort((a, b) => a.path.localeCompare(b.path));
|
return routes.sort((a, b) => a.path.localeCompare(b.path));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function createVersionTagsRoutes(loadedVersion: LoadedVersion) {
|
||||||
|
const versionTags = getVersionTags(loadedVersion.docs);
|
||||||
|
|
||||||
|
async function createTagsListPage() {
|
||||||
|
const tagsProp: PropTagsListPage['tags'] = Object.values(
|
||||||
|
versionTags,
|
||||||
|
).map((tagValue) => ({
|
||||||
|
name: tagValue.name,
|
||||||
|
permalink: tagValue.permalink,
|
||||||
|
count: tagValue.docIds.length,
|
||||||
|
}));
|
||||||
|
const tagsPropPath = await createData(
|
||||||
|
`${docuHash(`tags-list-${loadedVersion.versionName}-prop`)}.json`,
|
||||||
|
JSON.stringify(tagsProp, null, 2),
|
||||||
|
);
|
||||||
|
addRoute({
|
||||||
|
path: loadedVersion.tagsPath,
|
||||||
|
exact: true,
|
||||||
|
component: options.docTagsListComponent,
|
||||||
|
modules: {
|
||||||
|
tags: aliasedSource(tagsPropPath),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createTagDocListPage(tag: VersionTag) {
|
||||||
|
const tagProps = toTagDocListProp({
|
||||||
|
allTagsPath: loadedVersion.tagsPath,
|
||||||
|
tag,
|
||||||
|
docs: loadedVersion.docs,
|
||||||
|
});
|
||||||
|
const tagPropPath = await createData(
|
||||||
|
`${docuHash(`tag-${tag.permalink}`)}.json`,
|
||||||
|
JSON.stringify(tagProps, null, 2),
|
||||||
|
);
|
||||||
|
addRoute({
|
||||||
|
path: tag.permalink,
|
||||||
|
component: options.docTagDocListComponent,
|
||||||
|
exact: true,
|
||||||
|
modules: {
|
||||||
|
tag: aliasedSource(tagPropPath),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await createTagsListPage();
|
||||||
|
await Promise.all(Object.values(versionTags).map(createTagDocListPage));
|
||||||
|
}
|
||||||
|
|
||||||
async function doCreateVersionRoutes(
|
async function doCreateVersionRoutes(
|
||||||
loadedVersion: LoadedVersion,
|
loadedVersion: LoadedVersion,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
await createVersionTagsRoutes(loadedVersion);
|
||||||
|
|
||||||
const versionMetadata = toVersionMetadataProp(pluginId, loadedVersion);
|
const versionMetadata = toVersionMetadataProp(pluginId, loadedVersion);
|
||||||
const versionMetadataPropPath = await createData(
|
const versionMetadataPropPath = await createData(
|
||||||
`${docuHash(
|
`${docuHash(
|
||||||
|
|
|
@ -33,6 +33,8 @@ export const DEFAULT_OPTIONS: Omit<PluginOptions, 'id' | 'sidebarPath'> = {
|
||||||
numberPrefixParser: DefaultNumberPrefixParser,
|
numberPrefixParser: DefaultNumberPrefixParser,
|
||||||
docLayoutComponent: '@theme/DocPage',
|
docLayoutComponent: '@theme/DocPage',
|
||||||
docItemComponent: '@theme/DocItem',
|
docItemComponent: '@theme/DocItem',
|
||||||
|
docTagDocListComponent: '@theme/DocTagDocListPage',
|
||||||
|
docTagsListComponent: '@theme/DocTagsListPage',
|
||||||
remarkPlugins: [],
|
remarkPlugins: [],
|
||||||
rehypePlugins: [],
|
rehypePlugins: [],
|
||||||
beforeDefaultRemarkPlugins: [],
|
beforeDefaultRemarkPlugins: [],
|
||||||
|
@ -94,6 +96,12 @@ export const OptionsSchema = Joi.object({
|
||||||
.default(() => DEFAULT_OPTIONS.numberPrefixParser),
|
.default(() => DEFAULT_OPTIONS.numberPrefixParser),
|
||||||
docLayoutComponent: Joi.string().default(DEFAULT_OPTIONS.docLayoutComponent),
|
docLayoutComponent: Joi.string().default(DEFAULT_OPTIONS.docLayoutComponent),
|
||||||
docItemComponent: Joi.string().default(DEFAULT_OPTIONS.docItemComponent),
|
docItemComponent: Joi.string().default(DEFAULT_OPTIONS.docItemComponent),
|
||||||
|
docTagsListComponent: Joi.string().default(
|
||||||
|
DEFAULT_OPTIONS.docTagsListComponent,
|
||||||
|
),
|
||||||
|
docTagDocListComponent: Joi.string().default(
|
||||||
|
DEFAULT_OPTIONS.docTagDocListComponent,
|
||||||
|
),
|
||||||
remarkPlugins: RemarkPluginsSchema.default(DEFAULT_OPTIONS.remarkPlugins),
|
remarkPlugins: RemarkPluginsSchema.default(DEFAULT_OPTIONS.remarkPlugins),
|
||||||
rehypePlugins: RehypePluginsSchema.default(DEFAULT_OPTIONS.rehypePlugins),
|
rehypePlugins: RehypePluginsSchema.default(DEFAULT_OPTIONS.rehypePlugins),
|
||||||
beforeDefaultRemarkPlugins: RemarkPluginsSchema.default(
|
beforeDefaultRemarkPlugins: RemarkPluginsSchema.default(
|
||||||
|
|
|
@ -9,6 +9,9 @@ declare module '@docusaurus/plugin-content-docs-types' {
|
||||||
type VersionBanner = import('./types').VersionBanner;
|
type VersionBanner = import('./types').VersionBanner;
|
||||||
type GlobalDataVersion = import('./types').GlobalVersion;
|
type GlobalDataVersion = import('./types').GlobalVersion;
|
||||||
type GlobalDataDoc = import('./types').GlobalDoc;
|
type GlobalDataDoc = import('./types').GlobalDoc;
|
||||||
|
type VersionTag = import('./types').VersionTag;
|
||||||
|
|
||||||
|
export type {GlobalDataVersion, GlobalDataDoc};
|
||||||
|
|
||||||
export type PropVersionMetadata = {
|
export type PropVersionMetadata = {
|
||||||
pluginId: string;
|
pluginId: string;
|
||||||
|
@ -43,7 +46,26 @@ declare module '@docusaurus/plugin-content-docs-types' {
|
||||||
[sidebarId: string]: PropSidebarItem[];
|
[sidebarId: string]: PropSidebarItem[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type {GlobalDataVersion, GlobalDataDoc};
|
export type PropTagDocListDoc = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
permalink: string;
|
||||||
|
};
|
||||||
|
export type PropTagDocList = {
|
||||||
|
allTagsPath: string;
|
||||||
|
name: string; // normalized name/label of the tag
|
||||||
|
permalink: string; // pathname of the tag
|
||||||
|
docs: PropTagDocListDoc[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PropTagsListPage = {
|
||||||
|
tags: {
|
||||||
|
name: string;
|
||||||
|
permalink: string;
|
||||||
|
count: number;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/DocItem' {
|
declare module '@theme/DocItem' {
|
||||||
|
@ -79,6 +101,10 @@ declare module '@theme/DocItem' {
|
||||||
readonly version?: string;
|
readonly version?: string;
|
||||||
readonly previous?: {readonly permalink: string; readonly title: string};
|
readonly previous?: {readonly permalink: string; readonly title: string};
|
||||||
readonly next?: {readonly permalink: string; readonly title: string};
|
readonly next?: {readonly permalink: string; readonly title: string};
|
||||||
|
readonly tags: readonly {
|
||||||
|
readonly label: string;
|
||||||
|
readonly permalink: string;
|
||||||
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
|
@ -97,6 +123,19 @@ declare module '@theme/DocItem' {
|
||||||
export default DocItem;
|
export default DocItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module '@theme/DocItemFooter' {
|
||||||
|
import type {Props} from '@theme/DocItem';
|
||||||
|
|
||||||
|
export default function DocItemFooter(props: Props): JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@theme/DocTagsListPage' {
|
||||||
|
import type {PropTagsListPage} from '@docusaurus/plugin-content-docs-types';
|
||||||
|
|
||||||
|
export type Props = PropTagsListPage;
|
||||||
|
export default function DocItemFooter(props: Props): JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
declare module '@theme/DocVersionBanner' {
|
declare module '@theme/DocVersionBanner' {
|
||||||
import type {PropVersionMetadata} from '@docusaurus/plugin-content-docs-types';
|
import type {PropVersionMetadata} from '@docusaurus/plugin-content-docs-types';
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,17 @@ import {
|
||||||
SidebarItemDoc,
|
SidebarItemDoc,
|
||||||
SidebarItemLink,
|
SidebarItemLink,
|
||||||
SidebarItem,
|
SidebarItem,
|
||||||
|
VersionTag,
|
||||||
|
DocMetadata,
|
||||||
} from './types';
|
} from './types';
|
||||||
import {
|
import type {
|
||||||
PropSidebars,
|
PropSidebars,
|
||||||
PropVersionMetadata,
|
PropVersionMetadata,
|
||||||
PropSidebarItem,
|
PropSidebarItem,
|
||||||
|
PropTagDocList,
|
||||||
|
PropTagDocListDoc,
|
||||||
} from '@docusaurus/plugin-content-docs-types';
|
} from '@docusaurus/plugin-content-docs-types';
|
||||||
import {keyBy, mapValues} from 'lodash';
|
import {compact, keyBy, mapValues} from 'lodash';
|
||||||
|
|
||||||
export function toSidebarsProp(loadedVersion: LoadedVersion): PropSidebars {
|
export function toSidebarsProp(loadedVersion: LoadedVersion): PropSidebars {
|
||||||
const docsById = keyBy(loadedVersion.docs, (doc) => doc.id);
|
const docsById = keyBy(loadedVersion.docs, (doc) => doc.id);
|
||||||
|
@ -79,3 +83,34 @@ export function toVersionMetadataProp(
|
||||||
docsSidebars: toSidebarsProp(loadedVersion),
|
docsSidebars: toSidebarsProp(loadedVersion),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toTagDocListProp({
|
||||||
|
allTagsPath,
|
||||||
|
tag,
|
||||||
|
docs,
|
||||||
|
}: {
|
||||||
|
allTagsPath: string;
|
||||||
|
tag: VersionTag;
|
||||||
|
docs: Pick<DocMetadata, 'id' | 'title' | 'description' | 'permalink'>[];
|
||||||
|
}): PropTagDocList {
|
||||||
|
function toDocListProp(): PropTagDocListDoc[] {
|
||||||
|
const list = compact(
|
||||||
|
tag.docIds.map((id) => docs.find((doc) => doc.id === id)),
|
||||||
|
);
|
||||||
|
// Sort docs by title
|
||||||
|
list.sort((doc1, doc2) => doc1.title.localeCompare(doc2.title));
|
||||||
|
return list.map((doc) => ({
|
||||||
|
id: doc.id,
|
||||||
|
title: doc.title,
|
||||||
|
description: doc.description,
|
||||||
|
permalink: doc.permalink,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: tag.name,
|
||||||
|
permalink: tag.permalink,
|
||||||
|
docs: toDocListProp(),
|
||||||
|
allTagsPath,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
21
packages/docusaurus-plugin-content-docs/src/tags.ts
Normal file
21
packages/docusaurus-plugin-content-docs/src/tags.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
* 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 {groupTaggedItems} from '@docusaurus/utils';
|
||||||
|
import {VersionTags, DocMetadata} from './types';
|
||||||
|
import {mapValues} from 'lodash';
|
||||||
|
|
||||||
|
export function getVersionTags(docs: DocMetadata[]): VersionTags {
|
||||||
|
const groups = groupTaggedItems(docs, (doc) => doc.tags);
|
||||||
|
return mapValues(groups, (group) => {
|
||||||
|
return {
|
||||||
|
name: group.tag.label,
|
||||||
|
docIds: group.items.map((item) => item.id),
|
||||||
|
permalink: group.tag.permalink,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
|
@ -9,7 +9,8 @@
|
||||||
/// <reference types="@docusaurus/module-type-aliases" />
|
/// <reference types="@docusaurus/module-type-aliases" />
|
||||||
|
|
||||||
import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader';
|
import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader';
|
||||||
import {
|
import type {Tag, FrontMatterTag} from '@docusaurus/utils';
|
||||||
|
import type {
|
||||||
BrokenMarkdownLink as IBrokenMarkdownLink,
|
BrokenMarkdownLink as IBrokenMarkdownLink,
|
||||||
ContentPaths,
|
ContentPaths,
|
||||||
} from '@docusaurus/utils/lib/markdownLinks';
|
} from '@docusaurus/utils/lib/markdownLinks';
|
||||||
|
@ -28,6 +29,7 @@ export type VersionMetadata = ContentPaths & {
|
||||||
versionName: VersionName; // 1.0.0
|
versionName: VersionName; // 1.0.0
|
||||||
versionLabel: string; // Version 1.0.0
|
versionLabel: string; // Version 1.0.0
|
||||||
versionPath: string; // /baseUrl/docs/1.0.0
|
versionPath: string; // /baseUrl/docs/1.0.0
|
||||||
|
tagsPath: string;
|
||||||
versionEditUrl?: string | undefined;
|
versionEditUrl?: string | undefined;
|
||||||
versionEditUrlLocalized?: string | undefined;
|
versionEditUrlLocalized?: string | undefined;
|
||||||
versionBanner: VersionBanner;
|
versionBanner: VersionBanner;
|
||||||
|
@ -90,6 +92,8 @@ export type PluginOptions = MetadataOptions &
|
||||||
exclude: string[];
|
exclude: string[];
|
||||||
docLayoutComponent: string;
|
docLayoutComponent: string;
|
||||||
docItemComponent: string;
|
docItemComponent: string;
|
||||||
|
docTagDocListComponent: string;
|
||||||
|
docTagsListComponent: string;
|
||||||
admonitions: Record<string, unknown>;
|
admonitions: Record<string, unknown>;
|
||||||
disableVersioning: boolean;
|
disableVersioning: boolean;
|
||||||
includeCurrentVersion: boolean;
|
includeCurrentVersion: boolean;
|
||||||
|
@ -200,6 +204,7 @@ export type DocFrontMatter = {
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
id?: string;
|
id?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
|
tags?: FrontMatterTag[];
|
||||||
hide_title?: boolean;
|
hide_title?: boolean;
|
||||||
hide_table_of_contents?: boolean;
|
hide_table_of_contents?: boolean;
|
||||||
keywords?: string[];
|
keywords?: string[];
|
||||||
|
@ -227,6 +232,7 @@ export type DocMetadataBase = LastUpdateData & {
|
||||||
permalink: string;
|
permalink: string;
|
||||||
sidebarPosition?: number;
|
sidebarPosition?: number;
|
||||||
editUrl?: string | null;
|
editUrl?: string | null;
|
||||||
|
tags: Tag[];
|
||||||
frontMatter: DocFrontMatter & Record<string, unknown>;
|
frontMatter: DocFrontMatter & Record<string, unknown>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -244,6 +250,16 @@ export type DocMetadata = DocMetadataBase & {
|
||||||
export type SourceToPermalink = {
|
export type SourceToPermalink = {
|
||||||
[source: string]: string;
|
[source: string]: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type VersionTag = {
|
||||||
|
name: string; // normalized name/label of the tag
|
||||||
|
docIds: string[]; // all doc ids having this tag
|
||||||
|
permalink: string; // pathname of the tag
|
||||||
|
};
|
||||||
|
export type VersionTags = {
|
||||||
|
[key: string]: VersionTag;
|
||||||
|
};
|
||||||
|
|
||||||
export type LoadedVersion = VersionMetadata & {
|
export type LoadedVersion = VersionMetadata & {
|
||||||
versionPath: string;
|
versionPath: string;
|
||||||
mainDocId: string;
|
mainDocId: string;
|
||||||
|
|
|
@ -370,10 +370,15 @@ function createVersionMetadata({
|
||||||
// Because /docs/:route` should always be after `/docs/versionName/:route`.
|
// Because /docs/:route` should always be after `/docs/versionName/:route`.
|
||||||
const routePriority = versionPathPart === '' ? -1 : undefined;
|
const routePriority = versionPathPart === '' ? -1 : undefined;
|
||||||
|
|
||||||
|
// the path that will be used to refer the docs tags
|
||||||
|
// example below will be using /docs/tags
|
||||||
|
const tagsPath = normalizeUrl([versionPath, 'tags']);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
versionName,
|
versionName,
|
||||||
versionLabel,
|
versionLabel,
|
||||||
versionPath,
|
versionPath,
|
||||||
|
tagsPath,
|
||||||
versionEditUrl: versionEditUrls?.versionEditUrl,
|
versionEditUrl: versionEditUrls?.versionEditUrl,
|
||||||
versionEditUrlLocalized: versionEditUrls?.versionEditUrlLocalized,
|
versionEditUrlLocalized: versionEditUrls?.versionEditUrlLocalized,
|
||||||
versionBanner: getVersionBanner({
|
versionBanner: getVersionBanner({
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
* 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 Layout from '@theme/Layout';
|
||||||
|
import Link from '@docusaurus/Link';
|
||||||
|
import type {Props} from '@theme/BlogTagsListPage';
|
||||||
|
|
||||||
|
function DocTagsListPage(props: Props): JSX.Element {
|
||||||
|
const {tags} = props;
|
||||||
|
const renderAllTags = () => (
|
||||||
|
<>
|
||||||
|
{Object.keys(tags).map((tag) => (
|
||||||
|
<Link
|
||||||
|
href={tags[tag].permalink}
|
||||||
|
key={tag}
|
||||||
|
className="btn btn-primary list-inline-item my-2">
|
||||||
|
{tags[tag].name}{' '}
|
||||||
|
<span className="badge badge-light">{tags[tag].count}</span>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout title="Tags" description="Blog Tags">
|
||||||
|
<div className="container my-3 justify-content-center">
|
||||||
|
<h1 className="text-primary">Tags</h1>
|
||||||
|
<ul className="my-xl-4 list-inline">{renderAllTags()}</ul>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DocTagsListPage;
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "طي الشريط الجانبي",
|
"theme.docs.sidebar.collapseButtonTitle": "طي الشريط الجانبي",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "توسيع الشريط الجانبي",
|
"theme.docs.sidebar.expandButtonAriaLabel": "توسيع الشريط الجانبي",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "توسيع الشريط الجانبي",
|
"theme.docs.sidebar.expandButtonTitle": "توسيع الشريط الجانبي",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "احدث اصدار",
|
"theme.docs.versions.latestVersionLinkLabel": "احدث اصدار",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "للحصول على أحدث الوثائق، راجع {latestVersionLink} ({versionLabel}).",
|
"theme.docs.versions.latestVersionSuggestionLabel": "للحصول على أحدث الوثائق، راجع {latestVersionLink} ({versionLabel}).",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "هذه هي وثائق {siteTitle} {versionLabel}، التي لم تعد تتم صيانتها بشكل نشط.",
|
"theme.docs.versions.unmaintainedVersionLabel": "هذه هي وثائق {siteTitle} {versionLabel}، التي لم تعد تتم صيانتها بشكل نشط.",
|
||||||
|
|
|
@ -85,6 +85,10 @@
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel___DESCRIPTION": "The ARIA label and title attribute for expand button of doc sidebar",
|
"theme.docs.sidebar.expandButtonAriaLabel___DESCRIPTION": "The ARIA label and title attribute for expand button of doc sidebar",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "Expand sidebar",
|
"theme.docs.sidebar.expandButtonTitle": "Expand sidebar",
|
||||||
"theme.docs.sidebar.expandButtonTitle___DESCRIPTION": "The ARIA label and title attribute for expand button of doc sidebar",
|
"theme.docs.sidebar.expandButtonTitle___DESCRIPTION": "The ARIA label and title attribute for expand button of doc sidebar",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle___DESCRIPTION": "The title of the page for a docs tag",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged___DESCRIPTION": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "latest version",
|
"theme.docs.versions.latestVersionLinkLabel": "latest version",
|
||||||
"theme.docs.versions.latestVersionLinkLabel___DESCRIPTION": "The label used for the latest version suggestion link label",
|
"theme.docs.versions.latestVersionLinkLabel___DESCRIPTION": "The label used for the latest version suggestion link label",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).",
|
"theme.docs.versions.latestVersionSuggestionLabel": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "সাইডবারটি সঙ্কুচিত করুন",
|
"theme.docs.sidebar.collapseButtonTitle": "সাইডবারটি সঙ্কুচিত করুন",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "সাইডবারটি প্রসারিত করুন",
|
"theme.docs.sidebar.expandButtonAriaLabel": "সাইডবারটি প্রসারিত করুন",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "সাইডবারটি প্রসারিত করুন",
|
"theme.docs.sidebar.expandButtonTitle": "সাইডবারটি প্রসারিত করুন",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "লেটেস্ট ভার্সন",
|
"theme.docs.versions.latestVersionLinkLabel": "লেটেস্ট ভার্সন",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "আপ-টু-ডেট ডকুমেন্টেশনের জন্য, {latestVersionLink} ({versionLabel}) দেখুন।",
|
"theme.docs.versions.latestVersionSuggestionLabel": "আপ-টু-ডেট ডকুমেন্টেশনের জন্য, {latestVersionLink} ({versionLabel}) দেখুন।",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "এটি {siteTitle} {versionLabel} এর জন্যে ডকুমেন্টেশন, যা আর সক্রিয়ভাবে রক্ষণাবেক্ষণ করা হয় না।",
|
"theme.docs.versions.unmaintainedVersionLabel": "এটি {siteTitle} {versionLabel} এর জন্যে ডকুমেন্টেশন, যা আর সক্রিয়ভাবে রক্ষণাবেক্ষণ করা হয় না।",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "Zavřít postranní lištu",
|
"theme.docs.sidebar.collapseButtonTitle": "Zavřít postranní lištu",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "Otevřít postranní lištu",
|
"theme.docs.sidebar.expandButtonAriaLabel": "Otevřít postranní lištu",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "Otevřít postranní lištu",
|
"theme.docs.sidebar.expandButtonTitle": "Otevřít postranní lištu",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "Nejnovější verze",
|
"theme.docs.versions.latestVersionLinkLabel": "Nejnovější verze",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "Aktuální dokumentace viz {latestVersionLink} ({versionLabel}).",
|
"theme.docs.versions.latestVersionSuggestionLabel": "Aktuální dokumentace viz {latestVersionLink} ({versionLabel}).",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "Tato dokumentace je pro {siteTitle} {versionLabel}, která už není aktivně udržována.",
|
"theme.docs.versions.unmaintainedVersionLabel": "Tato dokumentace je pro {siteTitle} {versionLabel}, která už není aktivně udržována.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "Sammenlæg sidenavigation",
|
"theme.docs.sidebar.collapseButtonTitle": "Sammenlæg sidenavigation",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "Udvid sidenavigation",
|
"theme.docs.sidebar.expandButtonAriaLabel": "Udvid sidenavigation",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "Udvid sidenavigation",
|
"theme.docs.sidebar.expandButtonTitle": "Udvid sidenavigation",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "seneste version",
|
"theme.docs.versions.latestVersionLinkLabel": "seneste version",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "For seneste dokumentation, se {latestVersionLink} ({versionLabel}).",
|
"theme.docs.versions.latestVersionSuggestionLabel": "For seneste dokumentation, se {latestVersionLink} ({versionLabel}).",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "Dette er dokumentationen for {siteTitle} {versionLabel}, som ikke længere bliver aktivt vedligeholdt.",
|
"theme.docs.versions.unmaintainedVersionLabel": "Dette er dokumentationen for {siteTitle} {versionLabel}, som ikke længere bliver aktivt vedligeholdt.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "Seitenleiste einklappen",
|
"theme.docs.sidebar.collapseButtonTitle": "Seitenleiste einklappen",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "Seitenleiste ausklappen",
|
"theme.docs.sidebar.expandButtonAriaLabel": "Seitenleiste ausklappen",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "Seitenleiste ausklappen",
|
"theme.docs.sidebar.expandButtonTitle": "Seitenleiste ausklappen",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "letzte Version",
|
"theme.docs.versions.latestVersionLinkLabel": "letzte Version",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "Für die aktuellste Dokumentation bitte auf {latestVersionLink} ({versionLabel}) gehen.",
|
"theme.docs.versions.latestVersionSuggestionLabel": "Für die aktuellste Dokumentation bitte auf {latestVersionLink} ({versionLabel}) gehen.",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "Das ist die Dokumentation für {siteTitle} {versionLabel} und wird nicht weiter gewartet.",
|
"theme.docs.versions.unmaintainedVersionLabel": "Das ist die Dokumentation für {siteTitle} {versionLabel} und wird nicht weiter gewartet.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "Colapsar barra lateral",
|
"theme.docs.sidebar.collapseButtonTitle": "Colapsar barra lateral",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "Expandir barra lateral",
|
"theme.docs.sidebar.expandButtonAriaLabel": "Expandir barra lateral",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "Expandir barra lateral",
|
"theme.docs.sidebar.expandButtonTitle": "Expandir barra lateral",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "última versión",
|
"theme.docs.versions.latestVersionLinkLabel": "última versión",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "Para documentación actualizada, ver {latestVersionLink} ({versionLabel}).",
|
"theme.docs.versions.latestVersionSuggestionLabel": "Para documentación actualizada, ver {latestVersionLink} ({versionLabel}).",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "Esta es documentación para {siteTitle} {versionLabel}, que ya no se mantiene activamente.",
|
"theme.docs.versions.unmaintainedVersionLabel": "Esta es documentación para {siteTitle} {versionLabel}, que ya no se mantiene activamente.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "بستن نوار کناری",
|
"theme.docs.sidebar.collapseButtonTitle": "بستن نوار کناری",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "باز کردن نوار کناری",
|
"theme.docs.sidebar.expandButtonAriaLabel": "باز کردن نوار کناری",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "باز کردن نوار کناری",
|
"theme.docs.sidebar.expandButtonTitle": "باز کردن نوار کناری",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "آخرین نسخه",
|
"theme.docs.versions.latestVersionLinkLabel": "آخرین نسخه",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "برای دیدن آخرین نسخه این متن، نسخه {latestVersionLink} ({versionLabel}) را ببینید.",
|
"theme.docs.versions.latestVersionSuggestionLabel": "برای دیدن آخرین نسخه این متن، نسخه {latestVersionLink} ({versionLabel}) را ببینید.",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "نسخه {siteTitle} {versionLabel} دیگر به روزرسانی نمی شود.",
|
"theme.docs.versions.unmaintainedVersionLabel": "نسخه {siteTitle} {versionLabel} دیگر به روزرسانی نمی شود.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "Itupî ang sidebar",
|
"theme.docs.sidebar.collapseButtonTitle": "Itupî ang sidebar",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "Palakihin ang sidebar",
|
"theme.docs.sidebar.expandButtonAriaLabel": "Palakihin ang sidebar",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "Palakihin ang sidebar",
|
"theme.docs.sidebar.expandButtonTitle": "Palakihin ang sidebar",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "pinakahuling bersiyón",
|
"theme.docs.versions.latestVersionLinkLabel": "pinakahuling bersiyón",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "Para sa up-to-date na dokumentasyón, tingnan ang {latestVersionLink} ({versionLabel}).",
|
"theme.docs.versions.latestVersionSuggestionLabel": "Para sa up-to-date na dokumentasyón, tingnan ang {latestVersionLink} ({versionLabel}).",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "Ito ay dokumentasyón para sa {siteTitle} {versionLabel} na hindi na aktibong mine-maintain.",
|
"theme.docs.versions.unmaintainedVersionLabel": "Ito ay dokumentasyón para sa {siteTitle} {versionLabel} na hindi na aktibong mine-maintain.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "Réduire le menu latéral",
|
"theme.docs.sidebar.collapseButtonTitle": "Réduire le menu latéral",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "Déplier le menu latéral",
|
"theme.docs.sidebar.expandButtonAriaLabel": "Déplier le menu latéral",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "Déplier le menu latéral",
|
"theme.docs.sidebar.expandButtonTitle": "Déplier le menu latéral",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} avec \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "Un document tagué|{count} documents tagués",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "dernière version",
|
"theme.docs.versions.latestVersionLinkLabel": "dernière version",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "Pour une documentation à jour, consultez la {latestVersionLink} ({versionLabel}).",
|
"theme.docs.versions.latestVersionSuggestionLabel": "Pour une documentation à jour, consultez la {latestVersionLink} ({versionLabel}).",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "Ceci est la documentation de {siteTitle} {versionLabel}, qui n'est plus activement maintenue.",
|
"theme.docs.versions.unmaintainedVersionLabel": "Ceci est la documentation de {siteTitle} {versionLabel}, qui n'est plus activement maintenue.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "סגור",
|
"theme.docs.sidebar.collapseButtonTitle": "סגור",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "פתח",
|
"theme.docs.sidebar.expandButtonAriaLabel": "פתח",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "פתח",
|
"theme.docs.sidebar.expandButtonTitle": "פתח",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "גרסא אחרונה",
|
"theme.docs.versions.latestVersionLinkLabel": "גרסא אחרונה",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "לדוקומנטאציה עדכנית, ראה {latestVersionLink} ({versionLabel}).",
|
"theme.docs.versions.latestVersionSuggestionLabel": "לדוקומנטאציה עדכנית, ראה {latestVersionLink} ({versionLabel}).",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "דוקומנטאציה זו {siteTitle} {versionLabel}, כבר לא נתמכת.",
|
"theme.docs.versions.unmaintainedVersionLabel": "דוקומנטאציה זו {siteTitle} {versionLabel}, כבר לא נתמכת.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "साइडबार बंद करें",
|
"theme.docs.sidebar.collapseButtonTitle": "साइडबार बंद करें",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "साइडबार खोलें",
|
"theme.docs.sidebar.expandButtonAriaLabel": "साइडबार खोलें",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "साइडबार खोलें",
|
"theme.docs.sidebar.expandButtonTitle": "साइडबार खोलें",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "सबसे नया वर्जन",
|
"theme.docs.versions.latestVersionLinkLabel": "सबसे नया वर्जन",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "अप-टू-डेट डॉक्यूमेंटेशन के लिए {latestVersionLink} ({versionLabel}) देखें।",
|
"theme.docs.versions.latestVersionSuggestionLabel": "अप-टू-डेट डॉक्यूमेंटेशन के लिए {latestVersionLink} ({versionLabel}) देखें।",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "यह {siteTitle} {versionLabel} के लिए डॉक्यूमेंटेशन है, जिसे अब सक्रिय रूप से नहीं बनाए रखा गया है।",
|
"theme.docs.versions.unmaintainedVersionLabel": "यह {siteTitle} {versionLabel} के लिए डॉक्यूमेंटेशन है, जिसे अब सक्रिय रूप से नहीं बनाए रखा गया है।",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "サイドバーを隠す",
|
"theme.docs.sidebar.collapseButtonTitle": "サイドバーを隠す",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "サイドバーを開く",
|
"theme.docs.sidebar.expandButtonAriaLabel": "サイドバーを開く",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "サイドバーを開く",
|
"theme.docs.sidebar.expandButtonTitle": "サイドバーを開く",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "最新バージョン",
|
"theme.docs.versions.latestVersionLinkLabel": "最新バージョン",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "最新のドキュメントは{latestVersionLink} ({versionLabel}) を見てください。",
|
"theme.docs.versions.latestVersionSuggestionLabel": "最新のドキュメントは{latestVersionLink} ({versionLabel}) を見てください。",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "これは{siteTitle} {versionLabel}のドキュメントで現在はアクティブにメンテナンスされていません。",
|
"theme.docs.versions.unmaintainedVersionLabel": "これは{siteTitle} {versionLabel}のドキュメントで現在はアクティブにメンテナンスされていません。",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "사이드바 숨기기",
|
"theme.docs.sidebar.collapseButtonTitle": "사이드바 숨기기",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "사이드바 열기",
|
"theme.docs.sidebar.expandButtonAriaLabel": "사이드바 열기",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "사이드바 열기",
|
"theme.docs.sidebar.expandButtonTitle": "사이드바 열기",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "최신 버전",
|
"theme.docs.versions.latestVersionLinkLabel": "최신 버전",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "최신 문서는 {latestVersionLink} ({versionLabel})을 확인하세요.",
|
"theme.docs.versions.latestVersionSuggestionLabel": "최신 문서는 {latestVersionLink} ({versionLabel})을 확인하세요.",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "{siteTitle} {versionLabel} 문서는 업데이트되지 않습니다.",
|
"theme.docs.versions.unmaintainedVersionLabel": "{siteTitle} {versionLabel} 문서는 업데이트되지 않습니다.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "Zwiń boczny panel",
|
"theme.docs.sidebar.collapseButtonTitle": "Zwiń boczny panel",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "Rozszerz boczny panel",
|
"theme.docs.sidebar.expandButtonAriaLabel": "Rozszerz boczny panel",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "Rozszerz boczny panel",
|
"theme.docs.sidebar.expandButtonTitle": "Rozszerz boczny panel",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "bieżącej wersji",
|
"theme.docs.versions.latestVersionLinkLabel": "bieżącej wersji",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "Aby zobaczyć bieżącą dokumentację, przejdź do wersji {latestVersionLink} ({versionLabel}).",
|
"theme.docs.versions.latestVersionSuggestionLabel": "Aby zobaczyć bieżącą dokumentację, przejdź do wersji {latestVersionLink} ({versionLabel}).",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "Ta dokumentacja dotyczy {siteTitle} w wersji {versionLabel} i nie jest już aktywnie aktualizowana.",
|
"theme.docs.versions.unmaintainedVersionLabel": "Ta dokumentacja dotyczy {siteTitle} w wersji {versionLabel} i nie jest już aktywnie aktualizowana.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "Fechar painel lateral",
|
"theme.docs.sidebar.collapseButtonTitle": "Fechar painel lateral",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "Expandir painel lateral",
|
"theme.docs.sidebar.expandButtonAriaLabel": "Expandir painel lateral",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "Expandir painel lateral",
|
"theme.docs.sidebar.expandButtonTitle": "Expandir painel lateral",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "última versão",
|
"theme.docs.versions.latestVersionLinkLabel": "última versão",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "Para a documentação atualizada, veja: {latestVersionLink} ({versionLabel}).",
|
"theme.docs.versions.latestVersionSuggestionLabel": "Para a documentação atualizada, veja: {latestVersionLink} ({versionLabel}).",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "Esta é a documentação para {siteTitle} {versionLabel}, que não é mais mantida ativamente.",
|
"theme.docs.versions.unmaintainedVersionLabel": "Esta é a documentação para {siteTitle} {versionLabel}, que não é mais mantida ativamente.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "Colapsar barra lateral",
|
"theme.docs.sidebar.collapseButtonTitle": "Colapsar barra lateral",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "Expandir barra lateral",
|
"theme.docs.sidebar.expandButtonAriaLabel": "Expandir barra lateral",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "Expandir barra lateral",
|
"theme.docs.sidebar.expandButtonTitle": "Expandir barra lateral",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "última versão",
|
"theme.docs.versions.latestVersionLinkLabel": "última versão",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "Para a documentação atualizada, veja: {latestVersionLink} ({versionLabel}).",
|
"theme.docs.versions.latestVersionSuggestionLabel": "Para a documentação atualizada, veja: {latestVersionLink} ({versionLabel}).",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "Esta é a documentação para {siteTitle} {versionLabel}, que já não é mantida ativamente.",
|
"theme.docs.versions.unmaintainedVersionLabel": "Esta é a documentação para {siteTitle} {versionLabel}, que já não é mantida ativamente.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "Свернуть сайдбар",
|
"theme.docs.sidebar.collapseButtonTitle": "Свернуть сайдбар",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "Развернуть сайдбар",
|
"theme.docs.sidebar.expandButtonAriaLabel": "Развернуть сайдбар",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "Развернуть сайдбар",
|
"theme.docs.sidebar.expandButtonTitle": "Развернуть сайдбар",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "последней версии",
|
"theme.docs.versions.latestVersionLinkLabel": "последней версии",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "Актуальная документация находится на странице {latestVersionLink} ({versionLabel}).",
|
"theme.docs.versions.latestVersionSuggestionLabel": "Актуальная документация находится на странице {latestVersionLink} ({versionLabel}).",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "Это документация {siteTitle} для версии {versionLabel}, которая уже не поддерживается.",
|
"theme.docs.versions.unmaintainedVersionLabel": "Это документация {siteTitle} для версии {versionLabel}, которая уже не поддерживается.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "Kenar çubuğunu daralt",
|
"theme.docs.sidebar.collapseButtonTitle": "Kenar çubuğunu daralt",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "Kenar çubuğunu genişlet",
|
"theme.docs.sidebar.expandButtonAriaLabel": "Kenar çubuğunu genişlet",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "Kenar çubuğunu genişlet",
|
"theme.docs.sidebar.expandButtonTitle": "Kenar çubuğunu genişlet",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "en son sürüm",
|
"theme.docs.versions.latestVersionLinkLabel": "en son sürüm",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "Güncel belgeler için bkz. {latestVersionLink} ({versionLabel}).",
|
"theme.docs.versions.latestVersionSuggestionLabel": "Güncel belgeler için bkz. {latestVersionLink} ({versionLabel}).",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "Bu, {siteTitle} {versionLabel} dokümantasyonudur ve bakımı sonlanmıştır.",
|
"theme.docs.versions.unmaintainedVersionLabel": "Bu, {siteTitle} {versionLabel} dokümantasyonudur ve bakımı sonlanmıştır.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "Thu gọn thanh bên",
|
"theme.docs.sidebar.collapseButtonTitle": "Thu gọn thanh bên",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "Mở rộng thanh bên",
|
"theme.docs.sidebar.expandButtonAriaLabel": "Mở rộng thanh bên",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "Mở rộng thanh bên",
|
"theme.docs.sidebar.expandButtonTitle": "Mở rộng thanh bên",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "phiên bản mới nhất",
|
"theme.docs.versions.latestVersionLinkLabel": "phiên bản mới nhất",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "Để xem các cập nhật mới nhất, vui lòng xem phiên bản {latestVersionLink} ({versionLabel}).",
|
"theme.docs.versions.latestVersionSuggestionLabel": "Để xem các cập nhật mới nhất, vui lòng xem phiên bản {latestVersionLink} ({versionLabel}).",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "Đây là tài liệu của {siteTitle} {versionLabel}, hiện không còn được bảo trì.",
|
"theme.docs.versions.unmaintainedVersionLabel": "Đây là tài liệu của {siteTitle} {versionLabel}, hiện không còn được bảo trì.",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "收起侧边栏",
|
"theme.docs.sidebar.collapseButtonTitle": "收起侧边栏",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "展开侧边栏",
|
"theme.docs.sidebar.expandButtonAriaLabel": "展开侧边栏",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "展开侧边栏",
|
"theme.docs.sidebar.expandButtonTitle": "展开侧边栏",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "最新版本",
|
"theme.docs.versions.latestVersionLinkLabel": "最新版本",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "最新的文档请参阅 {latestVersionLink} ({versionLabel})。",
|
"theme.docs.versions.latestVersionSuggestionLabel": "最新的文档请参阅 {latestVersionLink} ({versionLabel})。",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "此为 {siteTitle} {versionLabel} 版的文档,现已不再积极维护。",
|
"theme.docs.versions.unmaintainedVersionLabel": "此为 {siteTitle} {versionLabel} 版的文档,现已不再积极维护。",
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
"theme.docs.sidebar.collapseButtonTitle": "收起側邊欄",
|
"theme.docs.sidebar.collapseButtonTitle": "收起側邊欄",
|
||||||
"theme.docs.sidebar.expandButtonAriaLabel": "展開側邊欄",
|
"theme.docs.sidebar.expandButtonAriaLabel": "展開側邊欄",
|
||||||
"theme.docs.sidebar.expandButtonTitle": "展開側邊欄",
|
"theme.docs.sidebar.expandButtonTitle": "展開側邊欄",
|
||||||
|
"theme.docs.tagDocListPageTitle": "{nDocsTagged} with \"{tagName}\"",
|
||||||
|
"theme.docs.tagDocListPageTitle.nDocsTagged": "One doc tagged|{count} docs tagged",
|
||||||
"theme.docs.versions.latestVersionLinkLabel": "最新版本",
|
"theme.docs.versions.latestVersionLinkLabel": "最新版本",
|
||||||
"theme.docs.versions.latestVersionSuggestionLabel": "最新的文件請參閱 {latestVersionLink} ({versionLabel})。",
|
"theme.docs.versions.latestVersionSuggestionLabel": "最新的文件請參閱 {latestVersionLink} ({versionLabel})。",
|
||||||
"theme.docs.versions.unmaintainedVersionLabel": "此為 {siteTitle} {versionLabel} 版的文件,現已不再積極維護。",
|
"theme.docs.versions.unmaintainedVersionLabel": "此為 {siteTitle} {versionLabel} 版的文件,現已不再積極維護。",
|
||||||
|
|
|
@ -18,6 +18,7 @@ import EditThisPage from '@theme/EditThisPage';
|
||||||
import type {Props} from '@theme/BlogPostItem';
|
import type {Props} from '@theme/BlogPostItem';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
import TagsListInline from '@theme/TagsListInline';
|
||||||
|
|
||||||
// Very simple pluralization: probably good enough for now
|
// Very simple pluralization: probably good enough for now
|
||||||
function useReadingTimePlural() {
|
function useReadingTimePlural() {
|
||||||
|
@ -156,22 +157,7 @@ function BlogPostItem(props: Props): JSX.Element {
|
||||||
})}>
|
})}>
|
||||||
{tags.length > 0 && (
|
{tags.length > 0 && (
|
||||||
<div className="col">
|
<div className="col">
|
||||||
<b>
|
<TagsListInline tags={tags} />
|
||||||
<Translate
|
|
||||||
id="theme.tags.tagsListLabel"
|
|
||||||
description="The label alongside a tag list">
|
|
||||||
Tags:
|
|
||||||
</Translate>
|
|
||||||
</b>
|
|
||||||
|
|
||||||
{tags.map(({label, permalink: tagPermalink}) => (
|
|
||||||
<Link
|
|
||||||
key={tagPermalink}
|
|
||||||
className="margin-horiz--sm"
|
|
||||||
to={tagPermalink}>
|
|
||||||
{label}
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -7,51 +7,17 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import Link from '@docusaurus/Link';
|
|
||||||
import BlogLayout from '@theme/BlogLayout';
|
import BlogLayout from '@theme/BlogLayout';
|
||||||
|
import TagsListByLetter from '@theme/TagsListByLetter';
|
||||||
import type {Props} from '@theme/BlogTagsListPage';
|
import type {Props} from '@theme/BlogTagsListPage';
|
||||||
import {translate} from '@docusaurus/Translate';
|
import {
|
||||||
import {ThemeClassNames} from '@docusaurus/theme-common';
|
ThemeClassNames,
|
||||||
|
translateTagsPageTitle,
|
||||||
function getCategoryOfTag(tag: string) {
|
} from '@docusaurus/theme-common';
|
||||||
// tag's category should be customizable
|
|
||||||
return tag[0].toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
function BlogTagsListPage(props: Props): JSX.Element {
|
function BlogTagsListPage(props: Props): JSX.Element {
|
||||||
const {tags, sidebar} = props;
|
const {tags, sidebar} = props;
|
||||||
const title = translate({
|
const title = translateTagsPageTitle();
|
||||||
id: 'theme.tags.tagsPageTitle',
|
|
||||||
message: 'Tags',
|
|
||||||
description: 'The title of the tag list page',
|
|
||||||
});
|
|
||||||
|
|
||||||
const tagCategories: {[category: string]: string[]} = {};
|
|
||||||
Object.keys(tags).forEach((tag) => {
|
|
||||||
const category = getCategoryOfTag(tag);
|
|
||||||
tagCategories[category] = tagCategories[category] || [];
|
|
||||||
tagCategories[category].push(tag);
|
|
||||||
});
|
|
||||||
const tagsList = Object.entries(tagCategories).sort(([a], [b]) =>
|
|
||||||
a.localeCompare(b),
|
|
||||||
);
|
|
||||||
const tagsSection = tagsList
|
|
||||||
.map(([category, tagsForCategory]) => (
|
|
||||||
<article key={category}>
|
|
||||||
<h2>{category}</h2>
|
|
||||||
{tagsForCategory.map((tag) => (
|
|
||||||
<Link
|
|
||||||
className="padding-right--md"
|
|
||||||
href={tags[tag].permalink}
|
|
||||||
key={tag}>
|
|
||||||
{tags[tag].name} ({tags[tag].count})
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
<hr />
|
|
||||||
</article>
|
|
||||||
))
|
|
||||||
.filter((item) => item != null);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BlogLayout
|
<BlogLayout
|
||||||
title={title}
|
title={title}
|
||||||
|
@ -63,7 +29,7 @@ function BlogTagsListPage(props: Props): JSX.Element {
|
||||||
}}
|
}}
|
||||||
sidebar={sidebar}>
|
sidebar={sidebar}>
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
<section className="margin-vert--lg">{tagsSection}</section>
|
<TagsListByLetter tags={Object.values(tags)} />
|
||||||
</BlogLayout>
|
</BlogLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ function BlogTagsPostPage(props: Props): JSX.Element {
|
||||||
<BlogLayout
|
<BlogLayout
|
||||||
title={title}
|
title={title}
|
||||||
wrapperClassName={ThemeClassNames.wrapper.blogPages}
|
wrapperClassName={ThemeClassNames.wrapper.blogPages}
|
||||||
pageClassName={ThemeClassNames.page.blogTagsPostPage}
|
pageClassName={ThemeClassNames.page.blogTagPostListPage}
|
||||||
searchMetadatas={{
|
searchMetadatas={{
|
||||||
// assign unique search tag to exclude this page from search results!
|
// assign unique search tag to exclude this page from search results!
|
||||||
tag: 'blog_tags_posts',
|
tag: 'blog_tags_posts',
|
||||||
|
|
|
@ -13,16 +13,15 @@ import useWindowSize from '@theme/hooks/useWindowSize';
|
||||||
import DocPaginator from '@theme/DocPaginator';
|
import DocPaginator from '@theme/DocPaginator';
|
||||||
import DocVersionBanner from '@theme/DocVersionBanner';
|
import DocVersionBanner from '@theme/DocVersionBanner';
|
||||||
import Seo from '@theme/Seo';
|
import Seo from '@theme/Seo';
|
||||||
import LastUpdated from '@theme/LastUpdated';
|
|
||||||
import type {Props} from '@theme/DocItem';
|
import type {Props} from '@theme/DocItem';
|
||||||
|
import DocItemFooter from '@theme/DocItemFooter';
|
||||||
import TOC from '@theme/TOC';
|
import TOC from '@theme/TOC';
|
||||||
import TOCCollapsible from '@theme/TOCCollapsible';
|
import TOCCollapsible from '@theme/TOCCollapsible';
|
||||||
import EditThisPage from '@theme/EditThisPage';
|
|
||||||
import {MainHeading} from '@theme/Heading';
|
import {MainHeading} from '@theme/Heading';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
function DocItem(props: Props): JSX.Element {
|
export default function DocItem(props: Props): JSX.Element {
|
||||||
const {content: DocContent, versionMetadata} = props;
|
const {content: DocContent, versionMetadata} = props;
|
||||||
const {metadata, frontMatter} = DocContent;
|
const {metadata, frontMatter} = DocContent;
|
||||||
const {
|
const {
|
||||||
|
@ -31,14 +30,7 @@ function DocItem(props: Props): JSX.Element {
|
||||||
hide_title: hideTitle,
|
hide_title: hideTitle,
|
||||||
hide_table_of_contents: hideTableOfContents,
|
hide_table_of_contents: hideTableOfContents,
|
||||||
} = frontMatter;
|
} = frontMatter;
|
||||||
const {
|
const {description, title} = metadata;
|
||||||
description,
|
|
||||||
title,
|
|
||||||
editUrl,
|
|
||||||
lastUpdatedAt,
|
|
||||||
formattedLastUpdatedAt,
|
|
||||||
lastUpdatedBy,
|
|
||||||
} = metadata;
|
|
||||||
|
|
||||||
const {pluginId} = useActivePlugin({failfast: true})!;
|
const {pluginId} = useActivePlugin({failfast: true})!;
|
||||||
const versions = useVersions(pluginId);
|
const versions = useVersions(pluginId);
|
||||||
|
@ -98,23 +90,7 @@ function DocItem(props: Props): JSX.Element {
|
||||||
<DocContent />
|
<DocContent />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{(editUrl || lastUpdatedAt || lastUpdatedBy) && (
|
<DocItemFooter {...props} />
|
||||||
<footer className="row docusaurus-mt-lg">
|
|
||||||
<div className="col">
|
|
||||||
{editUrl && <EditThisPage editUrl={editUrl} />}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={clsx('col', styles.lastUpdated)}>
|
|
||||||
{(lastUpdatedAt || lastUpdatedBy) && (
|
|
||||||
<LastUpdated
|
|
||||||
lastUpdatedAt={lastUpdatedAt}
|
|
||||||
formattedLastUpdatedAt={formattedLastUpdatedAt}
|
|
||||||
lastUpdatedBy={lastUpdatedBy}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
)}
|
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<DocPaginator metadata={metadata} />
|
<DocPaginator metadata={metadata} />
|
||||||
|
@ -129,5 +105,3 @@ function DocItem(props: Props): JSX.Element {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DocItem;
|
|
||||||
|
|
|
@ -10,21 +10,11 @@
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lastUpdated {
|
|
||||||
margin-top: 0.2rem;
|
|
||||||
font-style: italic;
|
|
||||||
font-size: smaller;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (min-width: 997px) {
|
@media only screen and (min-width: 997px) {
|
||||||
.docItemCol {
|
.docItemCol {
|
||||||
max-width: 75% !important;
|
max-width: 75% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lastUpdated {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prevent hydration FOUC, as the mobile TOC needs to be server-rendered */
|
/* Prevent hydration FOUC, as the mobile TOC needs to be server-rendered */
|
||||||
.tocMobile {
|
.tocMobile {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
/**
|
||||||
|
* 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 LastUpdated from '@theme/LastUpdated';
|
||||||
|
import type {Props} from '@theme/DocItem';
|
||||||
|
import EditThisPage from '@theme/EditThisPage';
|
||||||
|
import TagsListInline, {
|
||||||
|
Props as TagsListInlineProps,
|
||||||
|
} from '@theme/TagsListInline';
|
||||||
|
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
|
function TagsRow(props: TagsListInlineProps) {
|
||||||
|
return (
|
||||||
|
<div className="row margin-bottom--sm">
|
||||||
|
<div className="col">
|
||||||
|
<TagsListInline {...props} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
type EditMetaRowProps = Pick<
|
||||||
|
Props['content']['metadata'],
|
||||||
|
'editUrl' | 'lastUpdatedAt' | 'lastUpdatedBy' | 'formattedLastUpdatedAt'
|
||||||
|
>;
|
||||||
|
function EditMetaRow({
|
||||||
|
editUrl,
|
||||||
|
lastUpdatedAt,
|
||||||
|
lastUpdatedBy,
|
||||||
|
formattedLastUpdatedAt,
|
||||||
|
}: EditMetaRowProps) {
|
||||||
|
return (
|
||||||
|
<div className="row">
|
||||||
|
<div className="col">{editUrl && <EditThisPage editUrl={editUrl} />}</div>
|
||||||
|
|
||||||
|
<div className={clsx('col', styles.lastUpdated)}>
|
||||||
|
{(lastUpdatedAt || lastUpdatedBy) && (
|
||||||
|
<LastUpdated
|
||||||
|
lastUpdatedAt={lastUpdatedAt}
|
||||||
|
formattedLastUpdatedAt={formattedLastUpdatedAt}
|
||||||
|
lastUpdatedBy={lastUpdatedBy}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function DocItemFooter(props: Props): JSX.Element {
|
||||||
|
const {content: DocContent} = props;
|
||||||
|
const {metadata} = DocContent;
|
||||||
|
const {
|
||||||
|
editUrl,
|
||||||
|
lastUpdatedAt,
|
||||||
|
formattedLastUpdatedAt,
|
||||||
|
lastUpdatedBy,
|
||||||
|
tags,
|
||||||
|
} = metadata;
|
||||||
|
|
||||||
|
const canDisplayTagsRow = tags.length > 0;
|
||||||
|
const canDisplayEditMetaRow = !!(editUrl || lastUpdatedAt || lastUpdatedBy);
|
||||||
|
|
||||||
|
const canDisplayFooter = canDisplayTagsRow || canDisplayEditMetaRow;
|
||||||
|
|
||||||
|
if (!canDisplayFooter) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<footer className="docusaurus-mt-lg">
|
||||||
|
{canDisplayTagsRow && <TagsRow tags={tags} />}
|
||||||
|
{canDisplayEditMetaRow && (
|
||||||
|
<EditMetaRow
|
||||||
|
editUrl={editUrl}
|
||||||
|
lastUpdatedAt={lastUpdatedAt}
|
||||||
|
lastUpdatedBy={lastUpdatedBy}
|
||||||
|
formattedLastUpdatedAt={formattedLastUpdatedAt}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.lastUpdated {
|
||||||
|
margin-top: 0.2rem;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: smaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-width: 997px) {
|
||||||
|
.lastUpdated {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,7 +56,7 @@ function DocPageContent({
|
||||||
return (
|
return (
|
||||||
<Layout
|
<Layout
|
||||||
wrapperClassName={ThemeClassNames.wrapper.docPages}
|
wrapperClassName={ThemeClassNames.wrapper.docPages}
|
||||||
pageClassName={ThemeClassNames.page.docPage}
|
pageClassName={ThemeClassNames.page.docsDocPage}
|
||||||
searchMetadatas={{
|
searchMetadatas={{
|
||||||
version,
|
version,
|
||||||
tag: docVersionSearchTag(pluginId, version),
|
tag: docVersionSearchTag(pluginId, version),
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/**
|
||||||
|
* 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 Layout from '@theme/Layout';
|
||||||
|
import Link from '@docusaurus/Link';
|
||||||
|
import {ThemeClassNames, usePluralForm} from '@docusaurus/theme-common';
|
||||||
|
import type {
|
||||||
|
PropTagDocList,
|
||||||
|
PropTagDocListDoc,
|
||||||
|
} from '@docusaurus/plugin-content-docs-types';
|
||||||
|
import {translate} from '@docusaurus/Translate';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
tag: PropTagDocList;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Very simple pluralization: probably good enough for now
|
||||||
|
function useNDocsTaggedPlural() {
|
||||||
|
const {selectMessage} = usePluralForm();
|
||||||
|
return (count: number) =>
|
||||||
|
selectMessage(
|
||||||
|
count,
|
||||||
|
translate(
|
||||||
|
{
|
||||||
|
id: 'theme.docs.tagDocListPageTitle.nDocsTagged',
|
||||||
|
description:
|
||||||
|
'Pluralized label for "{count} docs tagged". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)',
|
||||||
|
message: 'One doc tagged|{count} docs tagged',
|
||||||
|
},
|
||||||
|
{count},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function DocItem({doc}: {doc: PropTagDocListDoc}): JSX.Element {
|
||||||
|
return (
|
||||||
|
<div className="margin-vert--lg">
|
||||||
|
<Link to={doc.permalink}>
|
||||||
|
<h2>{doc.title}</h2>
|
||||||
|
</Link>
|
||||||
|
{doc.description && <p>{doc.description}</p>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function DocTagDocListPage({tag}: Props): JSX.Element {
|
||||||
|
const nDocsTaggedPlural = useNDocsTaggedPlural();
|
||||||
|
const title = translate(
|
||||||
|
{
|
||||||
|
id: 'theme.docs.tagDocListPageTitle',
|
||||||
|
description: 'The title of the page for a docs tag',
|
||||||
|
message: '{nDocsTagged} with "{tagName}"',
|
||||||
|
},
|
||||||
|
{nDocsTagged: nDocsTaggedPlural(tag.docs.length), tagName: tag.name},
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout
|
||||||
|
title={title}
|
||||||
|
wrapperClassName={ThemeClassNames.wrapper.docPages}
|
||||||
|
pageClassName={ThemeClassNames.page.docsTagDocListPage}
|
||||||
|
searchMetadatas={{
|
||||||
|
// assign unique search tag to exclude this page from search results!
|
||||||
|
tag: 'doc_tag_doc_list',
|
||||||
|
}}>
|
||||||
|
<div className="container margin-vert--lg">
|
||||||
|
<div className="row">
|
||||||
|
<main className="col col--8 col--offset-2">
|
||||||
|
<header className="margin-bottom--xl">
|
||||||
|
<h1>{title}</h1>
|
||||||
|
<Link href={tag.allTagsPath}>View All Tags</Link>
|
||||||
|
</header>
|
||||||
|
<div className="margin-vert--lg">
|
||||||
|
{tag.docs.map((doc) => (
|
||||||
|
<DocItem key={doc.id} doc={doc} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
* 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 Layout from '@theme/Layout';
|
||||||
|
import {
|
||||||
|
ThemeClassNames,
|
||||||
|
translateTagsPageTitle,
|
||||||
|
} from '@docusaurus/theme-common';
|
||||||
|
import TagsListByLetter from '@theme/TagsListByLetter';
|
||||||
|
import type {Props} from '@theme/DocTagsListPage';
|
||||||
|
|
||||||
|
function DocTagsListPage({tags}: Props): JSX.Element {
|
||||||
|
const title = translateTagsPageTitle();
|
||||||
|
return (
|
||||||
|
<Layout
|
||||||
|
title={title}
|
||||||
|
wrapperClassName={ThemeClassNames.wrapper.docPages}
|
||||||
|
pageClassName={ThemeClassNames.page.docsTagsListPage}
|
||||||
|
searchMetadatas={{
|
||||||
|
// assign unique search tag to exclude this page from search results!
|
||||||
|
tag: 'doc_tags_list',
|
||||||
|
}}>
|
||||||
|
<div className="container margin-vert--lg">
|
||||||
|
<div className="row">
|
||||||
|
<main className="col col--8 col--offset-2">
|
||||||
|
<h1>{title}</h1>
|
||||||
|
<TagsListByLetter tags={tags} />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DocTagsListPage;
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
* 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 Link from '@docusaurus/Link';
|
||||||
|
import type {Props} from '@theme/TagsListByLetter';
|
||||||
|
import {listTagsByLetters, TagLetterEntry} from '@docusaurus/theme-common';
|
||||||
|
|
||||||
|
function TagLetterEntryItem({letterEntry}: {letterEntry: TagLetterEntry}) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>{letterEntry.letter}</h2>
|
||||||
|
{letterEntry.tags.map((tag) => (
|
||||||
|
<Link
|
||||||
|
className="padding-right--md"
|
||||||
|
href={tag.permalink}
|
||||||
|
key={tag.permalink}>
|
||||||
|
{tag.name} ({tag.count})
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TagsListByLetter({tags}: Props): JSX.Element {
|
||||||
|
const letterList = listTagsByLetters(tags);
|
||||||
|
return (
|
||||||
|
<section className="margin-vert--lg">
|
||||||
|
{letterList.map((letterEntry) => (
|
||||||
|
<TagLetterEntryItem
|
||||||
|
key={letterEntry.letter}
|
||||||
|
letterEntry={letterEntry}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TagsListByLetter;
|
|
@ -0,0 +1,30 @@
|
||||||
|
/**
|
||||||
|
* 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 Link from '@docusaurus/Link';
|
||||||
|
import Translate from '@docusaurus/Translate';
|
||||||
|
import type {Props} from '@theme/TagsListInline';
|
||||||
|
|
||||||
|
export default function TagsListInline({tags}: Props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<b>
|
||||||
|
<Translate
|
||||||
|
id="theme.tags.tagsListLabel"
|
||||||
|
description="The label alongside a tag list">
|
||||||
|
Tags:
|
||||||
|
</Translate>
|
||||||
|
</b>
|
||||||
|
{tags.map(({label, permalink: tagPermalink}) => (
|
||||||
|
<Link key={tagPermalink} className="margin-horiz--sm" to={tagPermalink}>
|
||||||
|
{label}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
20
packages/docusaurus-theme-classic/src/types.d.ts
vendored
20
packages/docusaurus-theme-classic/src/types.d.ts
vendored
|
@ -703,3 +703,23 @@ declare module '@theme/IconExternalLink' {
|
||||||
const IconExternalLink: (props: Props) => JSX.Element;
|
const IconExternalLink: (props: Props) => JSX.Element;
|
||||||
export default IconExternalLink;
|
export default IconExternalLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module '@theme/TagsListByLetter' {
|
||||||
|
export type TagsListItem = Readonly<{
|
||||||
|
name: string;
|
||||||
|
permalink: string;
|
||||||
|
count: number;
|
||||||
|
}>;
|
||||||
|
export type Props = Readonly<{
|
||||||
|
tags: readonly TagsListItem[];
|
||||||
|
}>;
|
||||||
|
export default function TagsListByLetter(props: Props): JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@theme/TagsListInline' {
|
||||||
|
export type Tag = Readonly<{label: string; permalink}>;
|
||||||
|
export type Props = Readonly<{
|
||||||
|
tags: readonly Tag[];
|
||||||
|
}>;
|
||||||
|
export default function TagsListInline(props: Props): JSX.Element;
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ const {mapValues, pickBy, difference, orderBy} = require('lodash');
|
||||||
const CodeDirPaths = [
|
const CodeDirPaths = [
|
||||||
path.join(__dirname, 'lib-next'),
|
path.join(__dirname, 'lib-next'),
|
||||||
// TODO other themes should rather define their own translations in the future?
|
// TODO other themes should rather define their own translations in the future?
|
||||||
|
path.join(__dirname, '..', 'docusaurus-theme-common', 'lib'),
|
||||||
path.join(__dirname, '..', 'docusaurus-theme-search-algolia', 'src', 'theme'),
|
path.join(__dirname, '..', 'docusaurus-theme-search-algolia', 'src', 'theme'),
|
||||||
path.join(__dirname, '..', 'docusaurus-theme-live-codeblock', 'src', 'theme'),
|
path.join(__dirname, '..', 'docusaurus-theme-live-codeblock', 'src', 'theme'),
|
||||||
path.join(__dirname, '..', 'docusaurus-plugin-pwa', 'src', 'theme'),
|
path.join(__dirname, '..', 'docusaurus-plugin-pwa', 'src', 'theme'),
|
||||||
|
|
|
@ -14,7 +14,7 @@ const {mapValues, pickBy} = require('lodash');
|
||||||
jest.setTimeout(15000);
|
jest.setTimeout(15000);
|
||||||
|
|
||||||
describe('update-code-translations', () => {
|
describe('update-code-translations', () => {
|
||||||
test(`to have base.json contain all the translations extracted from the theme. Please run "yarn workspace @docusaurus/theme-classic update-code-translations" to keep base.json up-to-date.`, async () => {
|
test(`to have base.json contain EXACTLY all the translations extracted from the theme. Please run "yarn workspace @docusaurus/theme-classic update-code-translations" to keep base.json up-to-date.`, async () => {
|
||||||
const baseMessages = pickBy(
|
const baseMessages = pickBy(
|
||||||
JSON.parse(
|
JSON.parse(
|
||||||
await fs.readFile(
|
await fs.readFile(
|
||||||
|
|
|
@ -28,7 +28,8 @@
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "2.0.0-beta.4"
|
"@docusaurus/module-type-aliases": "2.0.0-beta.4",
|
||||||
|
"lodash": "^4.17.20"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"prism-react-renderer": "^1.2.1",
|
"prism-react-renderer": "^1.2.1",
|
||||||
|
|
|
@ -68,3 +68,6 @@ export {
|
||||||
} from './utils/announcementBarUtils';
|
} from './utils/announcementBarUtils';
|
||||||
|
|
||||||
export {useLocalPathname} from './utils/useLocalPathname';
|
export {useLocalPathname} from './utils/useLocalPathname';
|
||||||
|
|
||||||
|
export {translateTagsPageTitle, listTagsByLetters} from './utils/tagsUtils';
|
||||||
|
export type {TagLetterEntry} from './utils/tagsUtils';
|
||||||
|
|
|
@ -11,8 +11,12 @@ export const ThemeClassNames = {
|
||||||
blogListPage: 'blog-list-page',
|
blogListPage: 'blog-list-page',
|
||||||
blogPostPage: 'blog-post-page',
|
blogPostPage: 'blog-post-page',
|
||||||
blogTagsListPage: 'blog-tags-list-page',
|
blogTagsListPage: 'blog-tags-list-page',
|
||||||
blogTagsPostPage: 'blog-tags-post-page',
|
blogTagPostListPage: 'blog-tags-post-list-page',
|
||||||
docPage: 'doc-page',
|
|
||||||
|
docsDocPage: 'docs-doc-page',
|
||||||
|
docsTagsListPage: 'docs-tags-list-page', // List of tags
|
||||||
|
docsTagDocListPage: 'docs-tags-doc-list-page', // Docs for a tag
|
||||||
|
|
||||||
mdxPage: 'mdx-page',
|
mdxPage: 'mdx-page',
|
||||||
},
|
},
|
||||||
wrapper: {
|
wrapper: {
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
* 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 {shuffle} from 'lodash';
|
||||||
|
import {listTagsByLetters} from '../tagsUtils';
|
||||||
|
|
||||||
|
describe('listTagsByLetters', () => {
|
||||||
|
type Param = Parameters<typeof listTagsByLetters>[0];
|
||||||
|
type Tag = Param[number];
|
||||||
|
type Result = ReturnType<typeof listTagsByLetters>;
|
||||||
|
|
||||||
|
test('Should create letters list', () => {
|
||||||
|
const tag1: Tag = {
|
||||||
|
name: 'tag1',
|
||||||
|
permalink: '/tag1',
|
||||||
|
count: 1,
|
||||||
|
};
|
||||||
|
const tag2: Tag = {
|
||||||
|
name: 'Tag2',
|
||||||
|
permalink: '/tag2',
|
||||||
|
count: 11,
|
||||||
|
};
|
||||||
|
const tagzxy: Tag = {
|
||||||
|
name: 'zxy',
|
||||||
|
permalink: '/zxy',
|
||||||
|
count: 987,
|
||||||
|
};
|
||||||
|
const tagAbc: Tag = {
|
||||||
|
name: 'Abc',
|
||||||
|
permalink: '/abc',
|
||||||
|
count: 123,
|
||||||
|
};
|
||||||
|
const tagdef: Tag = {
|
||||||
|
name: 'def',
|
||||||
|
permalink: '/def',
|
||||||
|
count: 1,
|
||||||
|
};
|
||||||
|
const tagaaa: Tag = {
|
||||||
|
name: 'aaa',
|
||||||
|
permalink: '/aaa',
|
||||||
|
count: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedResult: Result = [
|
||||||
|
{letter: 'A', tags: [tagaaa, tagAbc]},
|
||||||
|
{letter: 'D', tags: [tagdef]},
|
||||||
|
{letter: 'T', tags: [tag1, tag2]},
|
||||||
|
{letter: 'Z', tags: [tagzxy]},
|
||||||
|
];
|
||||||
|
|
||||||
|
// Input order shouldn't matter, output is always consistently sorted
|
||||||
|
expect(
|
||||||
|
listTagsByLetters([tag1, tag2, tagzxy, tagAbc, tagdef, tagaaa]),
|
||||||
|
).toEqual(expectedResult);
|
||||||
|
expect(
|
||||||
|
listTagsByLetters([tagzxy, tagdef, tagaaa, tag2, tagAbc, tag1]),
|
||||||
|
).toEqual(expectedResult);
|
||||||
|
expect(
|
||||||
|
listTagsByLetters(shuffle([tagzxy, tagdef, tagaaa, tag2, tagAbc, tag1])),
|
||||||
|
).toEqual(expectedResult);
|
||||||
|
});
|
||||||
|
});
|
48
packages/docusaurus-theme-common/src/utils/tagsUtils.ts
Normal file
48
packages/docusaurus-theme-common/src/utils/tagsUtils.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
* 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 {translate} from '@docusaurus/Translate';
|
||||||
|
|
||||||
|
export const translateTagsPageTitle = () =>
|
||||||
|
translate({
|
||||||
|
id: 'theme.tags.tagsPageTitle',
|
||||||
|
message: 'Tags',
|
||||||
|
description: 'The title of the tag list page',
|
||||||
|
});
|
||||||
|
|
||||||
|
type TagsListItem = Readonly<{name: string; permalink: string; count: number}>; // TODO remove duplicated type :s
|
||||||
|
|
||||||
|
export type TagLetterEntry = Readonly<{letter: string; tags: TagsListItem[]}>;
|
||||||
|
|
||||||
|
function getTagLetter(tag: string): string {
|
||||||
|
return tag[0].toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function listTagsByLetters(
|
||||||
|
tags: readonly TagsListItem[],
|
||||||
|
): TagLetterEntry[] {
|
||||||
|
// Group by letters
|
||||||
|
const groups: Record<string, TagsListItem[]> = {};
|
||||||
|
Object.values(tags).forEach((tag) => {
|
||||||
|
const letter = getTagLetter(tag.name);
|
||||||
|
groups[letter] = groups[letter] ?? [];
|
||||||
|
groups[letter].push(tag);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
Object.entries(groups)
|
||||||
|
// Sort letters
|
||||||
|
.sort(([letter1], [letter2]) => letter1.localeCompare(letter2))
|
||||||
|
.map(([letter, letterTags]) => {
|
||||||
|
// Sort tags inside a letter
|
||||||
|
const sortedTags = letterTags.sort((tag1, tag2) =>
|
||||||
|
tag1.name.localeCompare(tag2.name),
|
||||||
|
);
|
||||||
|
return {letter, tags: sortedTags};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
26
packages/docusaurus-utils-validation/src/JoiFrontMatter.ts
Normal file
26
packages/docusaurus-utils-validation/src/JoiFrontMatter.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/**
|
||||||
|
* 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 Joi from './Joi';
|
||||||
|
|
||||||
|
// Enhance the default Joi.string() type so that it can convert number to strings
|
||||||
|
// If user use frontmatter "tag: 2021", we shouldn't need to ask the user to write "tag: '2021'"
|
||||||
|
// Also yaml tries to convert patterns like "2019-01-01" to dates automatically
|
||||||
|
// see https://github.com/facebook/docusaurus/issues/4642
|
||||||
|
// see https://github.com/sideway/joi/issues/1442#issuecomment-823997884
|
||||||
|
const JoiFrontMatterString: Joi.Extension = {
|
||||||
|
type: 'string',
|
||||||
|
base: Joi.string(),
|
||||||
|
// Fix Yaml that tries to auto-convert many things to string out of the box
|
||||||
|
prepare: (value) => {
|
||||||
|
if (typeof value === 'number' || value instanceof Date) {
|
||||||
|
return {value: value.toString()};
|
||||||
|
}
|
||||||
|
return {value};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export const JoiFrontMatter: typeof Joi = Joi.extend(JoiFrontMatterString);
|
|
@ -6,7 +6,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Joi from '../Joi';
|
import Joi from '../Joi';
|
||||||
import {JoiFrontMatter, validateFrontMatter} from '../validationUtils';
|
import {JoiFrontMatter} from '../JoiFrontMatter';
|
||||||
|
import {validateFrontMatter} from '../validationUtils';
|
||||||
|
|
||||||
describe('validateFrontMatter', () => {
|
describe('validateFrontMatter', () => {
|
||||||
test('should accept good values', () => {
|
test('should accept good values', () => {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
// /!\ don't remove this export, as we recommend plugin authors to use it
|
// /!\ don't remove this export, as we recommend plugin authors to use it
|
||||||
export {default as Joi} from './Joi';
|
export {default as Joi} from './Joi';
|
||||||
|
export {JoiFrontMatter} from './JoiFrontMatter';
|
||||||
|
|
||||||
export * from './validationUtils';
|
export * from './validationUtils';
|
||||||
export * from './validationSchemas';
|
export * from './validationSchemas';
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
*/
|
*/
|
||||||
import Joi from './Joi';
|
import Joi from './Joi';
|
||||||
import {isValidPathname} from '@docusaurus/utils';
|
import {isValidPathname} from '@docusaurus/utils';
|
||||||
|
import type {Tag} from '@docusaurus/utils';
|
||||||
|
import {JoiFrontMatter} from './JoiFrontMatter';
|
||||||
|
|
||||||
export const PluginIdSchema = Joi.string()
|
export const PluginIdSchema = Joi.string()
|
||||||
.regex(/^[a-zA-Z_-]+$/)
|
.regex(/^[a-zA-Z_-]+$/)
|
||||||
|
@ -55,3 +57,13 @@ export const PathnameSchema = Joi.string()
|
||||||
.message(
|
.message(
|
||||||
'{{#label}} is not a valid pathname. Pathname should start with slash and not contain any domain or query string.',
|
'{{#label}} is not a valid pathname. Pathname should start with slash and not contain any domain or query string.',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const FrontMatterTagsSchema = JoiFrontMatter.array().items(
|
||||||
|
JoiFrontMatter.alternatives().try(
|
||||||
|
JoiFrontMatter.string().required(),
|
||||||
|
JoiFrontMatter.object<Tag>({
|
||||||
|
label: JoiFrontMatter.string().required(),
|
||||||
|
permalink: JoiFrontMatter.string().required(),
|
||||||
|
}).required(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
|
@ -99,24 +99,6 @@ export function normalizeThemeConfig<T>(
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enhance the default Joi.string() type so that it can convert number to strings
|
|
||||||
// If user use frontmatter "tag: 2021", we shouldn't need to ask the user to write "tag: '2021'"
|
|
||||||
// Also yaml tries to convert patterns like "2019-01-01" to dates automatically
|
|
||||||
// see https://github.com/facebook/docusaurus/issues/4642
|
|
||||||
// see https://github.com/sideway/joi/issues/1442#issuecomment-823997884
|
|
||||||
const JoiFrontMatterString: Joi.Extension = {
|
|
||||||
type: 'string',
|
|
||||||
base: Joi.string(),
|
|
||||||
// Fix Yaml that tries to auto-convert many things to string out of the box
|
|
||||||
prepare: (value) => {
|
|
||||||
if (typeof value === 'number' || value instanceof Date) {
|
|
||||||
return {value: value.toString()};
|
|
||||||
}
|
|
||||||
return {value};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
export const JoiFrontMatter: typeof Joi = Joi.extend(JoiFrontMatterString);
|
|
||||||
|
|
||||||
export function validateFrontMatter<T>(
|
export function validateFrontMatter<T>(
|
||||||
frontMatter: Record<string, unknown>,
|
frontMatter: Record<string, unknown>,
|
||||||
schema: Joi.ObjectSchema<T>,
|
schema: Joi.ObjectSchema<T>,
|
||||||
|
|
|
@ -12,7 +12,6 @@ import {
|
||||||
genChunkName,
|
genChunkName,
|
||||||
idx,
|
idx,
|
||||||
getSubFolder,
|
getSubFolder,
|
||||||
normalizeUrl,
|
|
||||||
posixPath,
|
posixPath,
|
||||||
objectWithKeySorted,
|
objectWithKeySorted,
|
||||||
aliasedSitePath,
|
aliasedSitePath,
|
||||||
|
@ -218,113 +217,6 @@ describe('load utils', () => {
|
||||||
expect(getSubFolder(testE, 'docs')).toBeNull();
|
expect(getSubFolder(testE, 'docs')).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('normalizeUrl', () => {
|
|
||||||
const asserts = [
|
|
||||||
{
|
|
||||||
input: ['/', ''],
|
|
||||||
output: '/',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['', '/'],
|
|
||||||
output: '/',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['/'],
|
|
||||||
output: '/',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: [''],
|
|
||||||
output: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['/', '/'],
|
|
||||||
output: '/',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['/', 'docs'],
|
|
||||||
output: '/docs',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['/', 'docs', 'en', 'next', 'blog'],
|
|
||||||
output: '/docs/en/next/blog',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['/test/', '/docs', 'ro', 'doc1'],
|
|
||||||
output: '/test/docs/ro/doc1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['/test/', '/', 'ro', 'doc1'],
|
|
||||||
output: '/test/ro/doc1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['/', '/', '2020/02/29/leap-day'],
|
|
||||||
output: '/2020/02/29/leap-day',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['', '/', 'ko', 'hello'],
|
|
||||||
output: '/ko/hello',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['hello', 'world'],
|
|
||||||
output: 'hello/world',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['http://www.google.com/', 'foo/bar', '?test=123'],
|
|
||||||
output: 'http://www.google.com/foo/bar?test=123',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['http:', 'www.google.com///', 'foo/bar', '?test=123'],
|
|
||||||
output: 'http://www.google.com/foo/bar?test=123',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['http://foobar.com', '', 'test'],
|
|
||||||
output: 'http://foobar.com/test',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['http://foobar.com', '', 'test', '/'],
|
|
||||||
output: 'http://foobar.com/test/',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['/', '', 'hello', '', '/', '/', '', '/', '/world'],
|
|
||||||
output: '/hello/world',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['', '', '/tt', 'ko', 'hello'],
|
|
||||||
output: '/tt/ko/hello',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['', '///hello///', '', '///world'],
|
|
||||||
output: '/hello/world',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['', '/hello/', ''],
|
|
||||||
output: '/hello/',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['', '/', ''],
|
|
||||||
output: '/',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['///', '///'],
|
|
||||||
output: '/',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: ['/', '/hello/world/', '///'],
|
|
||||||
output: '/hello/world/',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
asserts.forEach((testCase) => {
|
|
||||||
expect(normalizeUrl(testCase.input)).toBe(testCase.output);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(() =>
|
|
||||||
// @ts-expect-error undefined for test
|
|
||||||
normalizeUrl(['http:example.com', undefined]),
|
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
|
||||||
`"Url must be a string. Received undefined"`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('isValidPathname', () => {
|
test('isValidPathname', () => {
|
||||||
expect(isValidPathname('/')).toBe(true);
|
expect(isValidPathname('/')).toBe(true);
|
||||||
expect(isValidPathname('/hey')).toBe(true);
|
expect(isValidPathname('/hey')).toBe(true);
|
||||||
|
|
117
packages/docusaurus-utils/src/__tests__/normalizeUrl.test.ts
Normal file
117
packages/docusaurus-utils/src/__tests__/normalizeUrl.test.ts
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/**
|
||||||
|
* 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 {normalizeUrl} from '../normalizeUrl';
|
||||||
|
|
||||||
|
describe('normalizeUrl', () => {
|
||||||
|
test('should normalize urls correctly', () => {
|
||||||
|
const asserts = [
|
||||||
|
{
|
||||||
|
input: ['/', ''],
|
||||||
|
output: '/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['', '/'],
|
||||||
|
output: '/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['/'],
|
||||||
|
output: '/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: [''],
|
||||||
|
output: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['/', '/'],
|
||||||
|
output: '/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['/', 'docs'],
|
||||||
|
output: '/docs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['/', 'docs', 'en', 'next', 'blog'],
|
||||||
|
output: '/docs/en/next/blog',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['/test/', '/docs', 'ro', 'doc1'],
|
||||||
|
output: '/test/docs/ro/doc1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['/test/', '/', 'ro', 'doc1'],
|
||||||
|
output: '/test/ro/doc1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['/', '/', '2020/02/29/leap-day'],
|
||||||
|
output: '/2020/02/29/leap-day',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['', '/', 'ko', 'hello'],
|
||||||
|
output: '/ko/hello',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['hello', 'world'],
|
||||||
|
output: 'hello/world',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['http://www.google.com/', 'foo/bar', '?test=123'],
|
||||||
|
output: 'http://www.google.com/foo/bar?test=123',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['http:', 'www.google.com///', 'foo/bar', '?test=123'],
|
||||||
|
output: 'http://www.google.com/foo/bar?test=123',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['http://foobar.com', '', 'test'],
|
||||||
|
output: 'http://foobar.com/test',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['http://foobar.com', '', 'test', '/'],
|
||||||
|
output: 'http://foobar.com/test/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['/', '', 'hello', '', '/', '/', '', '/', '/world'],
|
||||||
|
output: '/hello/world',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['', '', '/tt', 'ko', 'hello'],
|
||||||
|
output: '/tt/ko/hello',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['', '///hello///', '', '///world'],
|
||||||
|
output: '/hello/world',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['', '/hello/', ''],
|
||||||
|
output: '/hello/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['', '/', ''],
|
||||||
|
output: '/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['///', '///'],
|
||||||
|
output: '/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['/', '/hello/world/', '///'],
|
||||||
|
output: '/hello/world/',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
asserts.forEach((testCase) => {
|
||||||
|
expect(normalizeUrl(testCase.input)).toBe(testCase.output);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(() =>
|
||||||
|
// @ts-expect-error undefined for test
|
||||||
|
normalizeUrl(['http:example.com', undefined]),
|
||||||
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`"Url must be a string. Received undefined"`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
183
packages/docusaurus-utils/src/__tests__/tags.test.ts
Normal file
183
packages/docusaurus-utils/src/__tests__/tags.test.ts
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
normalizeFrontMatterTag,
|
||||||
|
normalizeFrontMatterTags,
|
||||||
|
groupTaggedItems,
|
||||||
|
Tag,
|
||||||
|
} from '../tags';
|
||||||
|
|
||||||
|
describe('normalizeFrontMatterTag', () => {
|
||||||
|
type Input = Parameters<typeof normalizeFrontMatterTag>[1];
|
||||||
|
type Output = ReturnType<typeof normalizeFrontMatterTag>;
|
||||||
|
|
||||||
|
test('should normalize simple string tag', () => {
|
||||||
|
const tagsPath = '/all/tags';
|
||||||
|
const input: Input = 'tag';
|
||||||
|
const expectedOutput: Output = {
|
||||||
|
label: 'tag',
|
||||||
|
permalink: `${tagsPath}/tag`,
|
||||||
|
};
|
||||||
|
expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should normalize complex string tag', () => {
|
||||||
|
const tagsPath = '/all/tags';
|
||||||
|
const input: Input = 'some more Complex_tag';
|
||||||
|
const expectedOutput: Output = {
|
||||||
|
label: 'some more Complex_tag',
|
||||||
|
permalink: `${tagsPath}/some-more-complex-tag`,
|
||||||
|
};
|
||||||
|
expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should normalize simple object tag', () => {
|
||||||
|
const tagsPath = '/all/tags';
|
||||||
|
const input: Input = {label: 'tag', permalink: 'tagPermalink'};
|
||||||
|
const expectedOutput: Output = {
|
||||||
|
label: 'tag',
|
||||||
|
permalink: `${tagsPath}/tagPermalink`,
|
||||||
|
};
|
||||||
|
expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should normalize complex string tag', () => {
|
||||||
|
const tagsPath = '/all/tags';
|
||||||
|
const input: Input = {
|
||||||
|
label: 'tag complex Label',
|
||||||
|
permalink: '/MoreComplex/Permalink',
|
||||||
|
};
|
||||||
|
const expectedOutput: Output = {
|
||||||
|
label: 'tag complex Label',
|
||||||
|
permalink: `${tagsPath}/MoreComplex/Permalink`,
|
||||||
|
};
|
||||||
|
expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('normalizeFrontMatterTags', () => {
|
||||||
|
type Input = Parameters<typeof normalizeFrontMatterTags>[1];
|
||||||
|
type Output = ReturnType<typeof normalizeFrontMatterTags>;
|
||||||
|
|
||||||
|
test('should normalize string list', () => {
|
||||||
|
const tagsPath = '/all/tags';
|
||||||
|
const input: Input = ['tag 1', 'tag-1', 'tag 3', 'tag1', 'tag-2'];
|
||||||
|
// Keep user input order but remove tags that lead to same permalink
|
||||||
|
const expectedOutput: Output = [
|
||||||
|
{
|
||||||
|
label: 'tag 1',
|
||||||
|
permalink: `${tagsPath}/tag-1`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'tag 3',
|
||||||
|
permalink: `${tagsPath}/tag-3`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'tag-2',
|
||||||
|
permalink: `${tagsPath}/tag-2`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
expect(normalizeFrontMatterTags(tagsPath, input)).toEqual(expectedOutput);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should normalize complex mixed list', () => {
|
||||||
|
const tagsPath = '/all/tags';
|
||||||
|
const input: Input = [
|
||||||
|
'tag 1',
|
||||||
|
{label: 'tag-1', permalink: '/tag-1'},
|
||||||
|
'tag 3',
|
||||||
|
'tag1',
|
||||||
|
{label: 'tag 4', permalink: '/tag4Permalink'},
|
||||||
|
];
|
||||||
|
// Keep user input order but remove tags that lead to same permalink
|
||||||
|
const expectedOutput: Output = [
|
||||||
|
{
|
||||||
|
label: 'tag 1',
|
||||||
|
permalink: `${tagsPath}/tag-1`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'tag 3',
|
||||||
|
permalink: `${tagsPath}/tag-3`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'tag 4',
|
||||||
|
permalink: `${tagsPath}/tag4Permalink`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
expect(normalizeFrontMatterTags(tagsPath, input)).toEqual(expectedOutput);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('groupTaggedItems', () => {
|
||||||
|
type SomeTaggedItem = {
|
||||||
|
id: string;
|
||||||
|
nested: {
|
||||||
|
tags: Tag[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
function groupItems(items: SomeTaggedItem[]) {
|
||||||
|
return groupTaggedItems(items, (item) => item.nested.tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
type Input = Parameters<typeof groupItems>[0];
|
||||||
|
type Output = ReturnType<typeof groupItems>;
|
||||||
|
|
||||||
|
test('should group items by tag permalink', () => {
|
||||||
|
const tagGuide = {label: 'Guide', permalink: '/guide'};
|
||||||
|
const tagTutorial = {label: 'Tutorial', permalink: '/tutorial'};
|
||||||
|
const tagAPI = {label: 'API', permalink: '/api'};
|
||||||
|
|
||||||
|
// This one will be grouped under same permalink and label is ignored
|
||||||
|
const tagTutorialOtherLabel = {
|
||||||
|
label: 'TutorialOtherLabel',
|
||||||
|
permalink: '/tutorial',
|
||||||
|
};
|
||||||
|
|
||||||
|
const item1: SomeTaggedItem = {
|
||||||
|
id: '1',
|
||||||
|
nested: {
|
||||||
|
tags: [
|
||||||
|
tagGuide,
|
||||||
|
tagTutorial,
|
||||||
|
tagAPI,
|
||||||
|
// Add some duplicates on purpose: they should be filtered
|
||||||
|
tagGuide,
|
||||||
|
tagTutorialOtherLabel,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const item2: SomeTaggedItem = {
|
||||||
|
id: '2',
|
||||||
|
nested: {
|
||||||
|
tags: [tagAPI],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const item3: SomeTaggedItem = {
|
||||||
|
id: '3',
|
||||||
|
nested: {
|
||||||
|
tags: [tagTutorial],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const item4: SomeTaggedItem = {
|
||||||
|
id: '4',
|
||||||
|
nested: {
|
||||||
|
tags: [tagTutorialOtherLabel],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const input: Input = [item1, item2, item3, item4];
|
||||||
|
|
||||||
|
const expectedOutput: Output = {
|
||||||
|
'/guide': {tag: tagGuide, items: [item1]},
|
||||||
|
'/tutorial': {tag: tagTutorial, items: [item1, item3, item4]},
|
||||||
|
'/api': {tag: tagAPI, items: [item1, item2]},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(groupItems(input)).toEqual(expectedOutput);
|
||||||
|
});
|
||||||
|
});
|
|
@ -23,6 +23,10 @@ import resolvePathnameUnsafe from 'resolve-pathname';
|
||||||
|
|
||||||
import {posixPath as posixPathImport} from './posixPath';
|
import {posixPath as posixPathImport} from './posixPath';
|
||||||
import {simpleHash, docuHash} from './hashUtils';
|
import {simpleHash, docuHash} from './hashUtils';
|
||||||
|
import {normalizeUrl} from './normalizeUrl';
|
||||||
|
|
||||||
|
export * from './normalizeUrl';
|
||||||
|
export * from './tags';
|
||||||
|
|
||||||
export const posixPath = posixPathImport;
|
export const posixPath = posixPathImport;
|
||||||
|
|
||||||
|
@ -190,80 +194,6 @@ export function getSubFolder(file: string, refDir: string): string | null {
|
||||||
return match && match[1];
|
return match && match[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeUrl(rawUrls: string[]): string {
|
|
||||||
const urls = [...rawUrls];
|
|
||||||
const resultArray = [];
|
|
||||||
|
|
||||||
let hasStartingSlash = false;
|
|
||||||
let hasEndingSlash = false;
|
|
||||||
|
|
||||||
// If the first part is a plain protocol, we combine it with the next part.
|
|
||||||
if (urls[0].match(/^[^/:]+:\/*$/) && urls.length > 1) {
|
|
||||||
const first = urls.shift();
|
|
||||||
urls[0] = first + urls[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// There must be two or three slashes in the file protocol,
|
|
||||||
// two slashes in anything else.
|
|
||||||
const replacement = urls[0].match(/^file:\/\/\//) ? '$1:///' : '$1://';
|
|
||||||
urls[0] = urls[0].replace(/^([^/:]+):\/*/, replacement);
|
|
||||||
|
|
||||||
// eslint-disable-next-line
|
|
||||||
for (let i = 0; i < urls.length; i++) {
|
|
||||||
let component = urls[i];
|
|
||||||
|
|
||||||
if (typeof component !== 'string') {
|
|
||||||
throw new TypeError(`Url must be a string. Received ${typeof component}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component === '') {
|
|
||||||
if (i === urls.length - 1 && hasEndingSlash) {
|
|
||||||
resultArray.push('/');
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component !== '/') {
|
|
||||||
if (i > 0) {
|
|
||||||
// Removing the starting slashes for each component but the first.
|
|
||||||
component = component.replace(
|
|
||||||
/^[/]+/,
|
|
||||||
// Special case where the first element of rawUrls is empty ["", "/hello"] => /hello
|
|
||||||
component[0] === '/' && !hasStartingSlash ? '/' : '',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
hasEndingSlash = component[component.length - 1] === '/';
|
|
||||||
// Removing the ending slashes for each component but the last.
|
|
||||||
// For the last component we will combine multiple slashes to a single one.
|
|
||||||
component = component.replace(/[/]+$/, i < urls.length - 1 ? '' : '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
hasStartingSlash = true;
|
|
||||||
resultArray.push(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
let str = resultArray.join('/');
|
|
||||||
// Each input component is now separated by a single slash
|
|
||||||
// except the possible first plain protocol part.
|
|
||||||
|
|
||||||
// Remove trailing slash before parameters or hash.
|
|
||||||
str = str.replace(/\/(\?|&|#[^!])/g, '$1');
|
|
||||||
|
|
||||||
// Replace ? in parameters with &.
|
|
||||||
const parts = str.split('?');
|
|
||||||
str = parts.shift() + (parts.length > 0 ? '?' : '') + parts.join('&');
|
|
||||||
|
|
||||||
// Dedupe forward slashes in the entire path, avoiding protocol slashes.
|
|
||||||
str = str.replace(/([^:]\/)\/+/g, '$1');
|
|
||||||
|
|
||||||
// Dedupe forward slashes at the beginning of the path.
|
|
||||||
str = str.replace(/^\/+/g, '/');
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alias filepath relative to site directory, very useful so that we
|
* Alias filepath relative to site directory, very useful so that we
|
||||||
* don't expose user's site structure.
|
* don't expose user's site structure.
|
||||||
|
|
80
packages/docusaurus-utils/src/normalizeUrl.ts
Normal file
80
packages/docusaurus-utils/src/normalizeUrl.ts
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function normalizeUrl(rawUrls: string[]): string {
|
||||||
|
const urls = [...rawUrls];
|
||||||
|
const resultArray = [];
|
||||||
|
|
||||||
|
let hasStartingSlash = false;
|
||||||
|
let hasEndingSlash = false;
|
||||||
|
|
||||||
|
// If the first part is a plain protocol, we combine it with the next part.
|
||||||
|
if (urls[0].match(/^[^/:]+:\/*$/) && urls.length > 1) {
|
||||||
|
const first = urls.shift();
|
||||||
|
urls[0] = first + urls[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// There must be two or three slashes in the file protocol,
|
||||||
|
// two slashes in anything else.
|
||||||
|
const replacement = urls[0].match(/^file:\/\/\//) ? '$1:///' : '$1://';
|
||||||
|
urls[0] = urls[0].replace(/^([^/:]+):\/*/, replacement);
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
for (let i = 0; i < urls.length; i++) {
|
||||||
|
let component = urls[i];
|
||||||
|
|
||||||
|
if (typeof component !== 'string') {
|
||||||
|
throw new TypeError(`Url must be a string. Received ${typeof component}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component === '') {
|
||||||
|
if (i === urls.length - 1 && hasEndingSlash) {
|
||||||
|
resultArray.push('/');
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component !== '/') {
|
||||||
|
if (i > 0) {
|
||||||
|
// Removing the starting slashes for each component but the first.
|
||||||
|
component = component.replace(
|
||||||
|
/^[/]+/,
|
||||||
|
// Special case where the first element of rawUrls is empty ["", "/hello"] => /hello
|
||||||
|
component[0] === '/' && !hasStartingSlash ? '/' : '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
hasEndingSlash = component[component.length - 1] === '/';
|
||||||
|
// Removing the ending slashes for each component but the last.
|
||||||
|
// For the last component we will combine multiple slashes to a single one.
|
||||||
|
component = component.replace(/[/]+$/, i < urls.length - 1 ? '' : '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
hasStartingSlash = true;
|
||||||
|
resultArray.push(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
let str = resultArray.join('/');
|
||||||
|
// Each input component is now separated by a single slash
|
||||||
|
// except the possible first plain protocol part.
|
||||||
|
|
||||||
|
// Remove trailing slash before parameters or hash.
|
||||||
|
str = str.replace(/\/(\?|&|#[^!])/g, '$1');
|
||||||
|
|
||||||
|
// Replace ? in parameters with &.
|
||||||
|
const parts = str.split('?');
|
||||||
|
str = parts.shift() + (parts.length > 0 ? '?' : '') + parts.join('&');
|
||||||
|
|
||||||
|
// Dedupe forward slashes in the entire path, avoiding protocol slashes.
|
||||||
|
str = str.replace(/([^:]\/)\/+/g, '$1');
|
||||||
|
|
||||||
|
// Dedupe forward slashes at the beginning of the path.
|
||||||
|
str = str.replace(/^\/+/g, '/');
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
100
packages/docusaurus-utils/src/tags.ts
Normal file
100
packages/docusaurus-utils/src/tags.ts
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/**
|
||||||
|
* 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 {kebabCase, uniq, uniqBy} from 'lodash';
|
||||||
|
import {normalizeUrl} from './normalizeUrl';
|
||||||
|
|
||||||
|
export type Tag = {
|
||||||
|
label: string;
|
||||||
|
permalink: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FrontMatterTag = string | Tag;
|
||||||
|
|
||||||
|
export function normalizeFrontMatterTag(
|
||||||
|
tagsPath: string,
|
||||||
|
frontMatterTag: FrontMatterTag,
|
||||||
|
): Tag {
|
||||||
|
function toTagObject(tagString: string): Tag {
|
||||||
|
return {
|
||||||
|
label: tagString,
|
||||||
|
permalink: kebabCase(tagString),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO maybe make ensure the permalink is valid url path?
|
||||||
|
function normalizeTagPermalink(permalink: string): string {
|
||||||
|
// note: we always apply tagsPath on purpose
|
||||||
|
// for versioned docs, v1/doc.md and v2/doc.md tags with custom permalinks don't lead to the same created page
|
||||||
|
// tagsPath is different for each doc version
|
||||||
|
return normalizeUrl([tagsPath, permalink]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tag: Tag =
|
||||||
|
typeof frontMatterTag === 'string'
|
||||||
|
? toTagObject(frontMatterTag)
|
||||||
|
: frontMatterTag;
|
||||||
|
|
||||||
|
return {
|
||||||
|
label: tag.label,
|
||||||
|
permalink: normalizeTagPermalink(tag.permalink),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeFrontMatterTags(
|
||||||
|
tagsPath: string,
|
||||||
|
frontMatterTags: FrontMatterTag[] | undefined,
|
||||||
|
): Tag[] {
|
||||||
|
const tags =
|
||||||
|
frontMatterTags?.map((tag) => normalizeFrontMatterTag(tagsPath, tag)) ?? [];
|
||||||
|
|
||||||
|
return uniqBy(tags, (tag) => tag.permalink);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TaggedItemGroup<Item> = {
|
||||||
|
tag: Tag;
|
||||||
|
items: Item[];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Permits to group docs/blogPosts by tag (provided by FrontMatter)
|
||||||
|
// Note: groups are indexed by permalink, because routes must be unique in the end
|
||||||
|
// Labels may vary on 2 md files but they are normalized.
|
||||||
|
// Docs with label='some label' and label='some-label' should end-up in the same group/page in the end
|
||||||
|
// We can't create 2 routes /some-label because one would override the other
|
||||||
|
export function groupTaggedItems<Item>(
|
||||||
|
items: Item[],
|
||||||
|
getItemTags: (item: Item) => Tag[],
|
||||||
|
): Record<string, TaggedItemGroup<Item>> {
|
||||||
|
const result: Record<string, TaggedItemGroup<Item>> = {};
|
||||||
|
|
||||||
|
function handleItemTag(item: Item, tag: Tag) {
|
||||||
|
// Init missing tag groups
|
||||||
|
// TODO: it's not really clear what should be the behavior if 2 items have the same tag but the permalink is different for each
|
||||||
|
// For now, the first tag found wins
|
||||||
|
result[tag.permalink] = result[tag.permalink] ?? {
|
||||||
|
tag,
|
||||||
|
items: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add item to group
|
||||||
|
result[tag.permalink].items.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
items.forEach((item) => {
|
||||||
|
getItemTags(item).forEach((tag) => {
|
||||||
|
handleItemTag(item, tag);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// If user add twice the same tag to a md doc (weird but possible),
|
||||||
|
// we don't want the item to appear twice in the list...
|
||||||
|
Object.values(result).forEach((group) => {
|
||||||
|
group.items = uniq(group.items);
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
---
|
---
|
||||||
slug: /
|
slug: /
|
||||||
|
tags: [a, b, c, some tag]
|
||||||
---
|
---
|
||||||
|
|
||||||
# Docs tests
|
# Docs tests
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
---
|
||||||
|
tags: [a, e, some-tag, some_tag]
|
||||||
|
---
|
||||||
|
|
||||||
# Another test page
|
# Another test page
|
||||||
|
|
||||||
[Test link](./folder%20with%20space/doc%201.md)
|
[Test link](./folder%20with%20space/doc%201.md)
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
---
|
||||||
|
tags:
|
||||||
|
- b
|
||||||
|
- label: d
|
||||||
|
permalink: d-custom-permalink
|
||||||
|
---
|
||||||
|
|
||||||
# Standalone doc
|
# Standalone doc
|
||||||
|
|
||||||
This doc is not in any sidebar, on purpose, to measure the build size impact of the huge sidebar
|
This doc is not in any sidebar, on purpose, to measure the build size impact of the huge sidebar
|
||||||
|
|
|
@ -42,6 +42,8 @@ Accepted fields:
|
||||||
| `numberPrefixParser` | <code>boolean | PrefixParser</code> | _Omitted_ | Custom parsing logic to extract number prefixes from file names. Use `false` to disable this behavior and leave the docs untouched, and `true` to use the default parser. See also [Using number prefixes](/docs/sidebar#using-number-prefixes) |
|
| `numberPrefixParser` | <code>boolean | PrefixParser</code> | _Omitted_ | Custom parsing logic to extract number prefixes from file names. Use `false` to disable this behavior and leave the docs untouched, and `true` to use the default parser. See also [Using number prefixes](/docs/sidebar#using-number-prefixes) |
|
||||||
| `docLayoutComponent` | `string` | `'@theme/DocPage'` | Root Layout component of each doc page. |
|
| `docLayoutComponent` | `string` | `'@theme/DocPage'` | Root Layout component of each doc page. |
|
||||||
| `docItemComponent` | `string` | `'@theme/DocItem'` | Main doc container, with TOC, pagination, etc. |
|
| `docItemComponent` | `string` | `'@theme/DocItem'` | Main doc container, with TOC, pagination, etc. |
|
||||||
|
| `docTagsListComponent` | `string` | `'@theme/DocTagsListPage'` | Root component of the tags list page |
|
||||||
|
| `docTagDocListComponent` | `string` | `'@theme/DocTagDocListPage'` | Root component of the "docs containing tag" page. |
|
||||||
| `remarkPlugins` | `any[]` | `[]` | Remark plugins passed to MDX. |
|
| `remarkPlugins` | `any[]` | `[]` | Remark plugins passed to MDX. |
|
||||||
| `rehypePlugins` | `any[]` | `[]` | Rehype plugins passed to MDX. |
|
| `rehypePlugins` | `any[]` | `[]` | Rehype plugins passed to MDX. |
|
||||||
| `beforeDefaultRemarkPlugins` | `any[]` | `[]` | Custom Remark plugins passed to MDX before the default Docusaurus Remark plugins. |
|
| `beforeDefaultRemarkPlugins` | `any[]` | `[]` | Custom Remark plugins passed to MDX before the default Docusaurus Remark plugins. |
|
||||||
|
@ -249,9 +251,14 @@ Accepted fields:
|
||||||
| `description` | `string` | The first line of Markdown content | The description of your document, which will become the `<meta name="description" content="..."/>` and `<meta property="og:description" content="..."/>` in `<head>`, used by search engines. |
|
| `description` | `string` | The first line of Markdown content | The description of your document, which will become the `<meta name="description" content="..."/>` and `<meta property="og:description" content="..."/>` in `<head>`, used by search engines. |
|
||||||
| `image` | `string` | `undefined` | Cover or thumbnail image that will be used when displaying the link to your post. |
|
| `image` | `string` | `undefined` | Cover or thumbnail image that will be used when displaying the link to your post. |
|
||||||
| `slug` | `string` | File path | Allows to customize the document url (`/<routeBasePath>/<slug>`). Support multiple patterns: `slug: my-doc`, `slug: /my/path/myDoc`, `slug: /`. |
|
| `slug` | `string` | File path | Allows to customize the document url (`/<routeBasePath>/<slug>`). Support multiple patterns: `slug: my-doc`, `slug: /my/path/myDoc`, `slug: /`. |
|
||||||
|
| `tags` | `Tag[]` | `undefined` | A list of strings or objects of two string fields `label` and `permalink` to tag to your docs. |
|
||||||
|
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type Tag = string | {label: string; permalink: string};
|
||||||
|
```
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue