mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-01 19:27:48 +02:00
refactor(content-{blog,docs}): unify handling of tags (#7117)
This commit is contained in:
parent
ca718ccac0
commit
1156be3f20
24 changed files with 170 additions and 178 deletions
|
@ -8,7 +8,7 @@ exports[`blog plugin works on blog tags without pagination 1`] = `
|
||||||
"/another/tags",
|
"/another/tags",
|
||||||
"/another/tags2",
|
"/another/tags2",
|
||||||
],
|
],
|
||||||
"name": "tag1",
|
"label": "tag1",
|
||||||
"pages": [
|
"pages": [
|
||||||
{
|
{
|
||||||
"items": [
|
"items": [
|
||||||
|
@ -36,7 +36,7 @@ exports[`blog plugin works on blog tags without pagination 1`] = `
|
||||||
"/another/tags",
|
"/another/tags",
|
||||||
"/another/tags2",
|
"/another/tags2",
|
||||||
],
|
],
|
||||||
"name": "tag2",
|
"label": "tag2",
|
||||||
"pages": [
|
"pages": [
|
||||||
{
|
{
|
||||||
"items": [
|
"items": [
|
||||||
|
@ -69,7 +69,7 @@ exports[`blog plugin works with blog tags 1`] = `
|
||||||
"/another/tags",
|
"/another/tags",
|
||||||
"/another/tags2",
|
"/another/tags2",
|
||||||
],
|
],
|
||||||
"name": "tag1",
|
"label": "tag1",
|
||||||
"pages": [
|
"pages": [
|
||||||
{
|
{
|
||||||
"items": [
|
"items": [
|
||||||
|
@ -112,7 +112,7 @@ exports[`blog plugin works with blog tags 1`] = `
|
||||||
"/another/tags",
|
"/another/tags",
|
||||||
"/another/tags2",
|
"/another/tags2",
|
||||||
],
|
],
|
||||||
"name": "tag2",
|
"label": "tag2",
|
||||||
"pages": [
|
"pages": [
|
||||||
{
|
{
|
||||||
"items": [
|
"items": [
|
||||||
|
|
|
@ -114,7 +114,7 @@ export function getBlogTags({
|
||||||
);
|
);
|
||||||
|
|
||||||
return _.mapValues(groups, ({tag, items: tagBlogPosts}) => ({
|
return _.mapValues(groups, ({tag, items: tagBlogPosts}) => ({
|
||||||
name: tag.label,
|
label: tag.label,
|
||||||
items: tagBlogPosts.map((item) => item.id),
|
items: tagBlogPosts.map((item) => item.id),
|
||||||
permalink: tag.permalink,
|
permalink: tag.permalink,
|
||||||
pages: paginateBlogPosts({
|
pages: paginateBlogPosts({
|
||||||
|
|
|
@ -30,7 +30,13 @@ import type {
|
||||||
BlogContentPaths,
|
BlogContentPaths,
|
||||||
BlogMarkdownLoaderOptions,
|
BlogMarkdownLoaderOptions,
|
||||||
} from './types';
|
} from './types';
|
||||||
import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types';
|
import type {
|
||||||
|
LoadContext,
|
||||||
|
Plugin,
|
||||||
|
HtmlTags,
|
||||||
|
TagsListItem,
|
||||||
|
TagModule,
|
||||||
|
} from '@docusaurus/types';
|
||||||
import {
|
import {
|
||||||
generateBlogPosts,
|
generateBlogPosts,
|
||||||
getSourceToPermalink,
|
getSourceToPermalink,
|
||||||
|
@ -43,7 +49,6 @@ import type {
|
||||||
BlogPostFrontMatter,
|
BlogPostFrontMatter,
|
||||||
BlogPostMetadata,
|
BlogPostMetadata,
|
||||||
Assets,
|
Assets,
|
||||||
TagModule,
|
|
||||||
} from '@docusaurus/plugin-content-blog';
|
} from '@docusaurus/plugin-content-blog';
|
||||||
|
|
||||||
export default async function pluginContentBlog(
|
export default async function pluginContentBlog(
|
||||||
|
@ -117,6 +122,8 @@ export default async function pluginContentBlog(
|
||||||
blogSidebarTitle,
|
blogSidebarTitle,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
|
const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
|
||||||
|
const blogTagsListPath = normalizeUrl([baseBlogUrl, tagsBasePath]);
|
||||||
const blogPosts = await generateBlogPosts(contentPaths, context, options);
|
const blogPosts = await generateBlogPosts(contentPaths, context, options);
|
||||||
|
|
||||||
if (!blogPosts.length) {
|
if (!blogPosts.length) {
|
||||||
|
@ -125,7 +132,7 @@ export default async function pluginContentBlog(
|
||||||
blogPosts: [],
|
blogPosts: [],
|
||||||
blogListPaginated: [],
|
blogListPaginated: [],
|
||||||
blogTags: {},
|
blogTags: {},
|
||||||
blogTagsListPath: null,
|
blogTagsListPath,
|
||||||
blogTagsPaginated: [],
|
blogTagsPaginated: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -150,8 +157,6 @@ export default async function pluginContentBlog(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
|
|
||||||
|
|
||||||
const blogListPaginated: BlogPaginated[] = paginateBlogPosts({
|
const blogListPaginated: BlogPaginated[] = paginateBlogPosts({
|
||||||
blogPosts,
|
blogPosts,
|
||||||
blogTitle,
|
blogTitle,
|
||||||
|
@ -167,11 +172,6 @@ export default async function pluginContentBlog(
|
||||||
blogTitle,
|
blogTitle,
|
||||||
});
|
});
|
||||||
|
|
||||||
const tagsPath = normalizeUrl([baseBlogUrl, tagsBasePath]);
|
|
||||||
|
|
||||||
const blogTagsListPath =
|
|
||||||
Object.keys(blogTags).length > 0 ? tagsPath : null;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
blogSidebarTitle,
|
blogSidebarTitle,
|
||||||
blogPosts,
|
blogPosts,
|
||||||
|
@ -307,30 +307,47 @@ export default async function pluginContentBlog(
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Tags.
|
// Tags. This is the last part so we early-return if there are no tags.
|
||||||
if (blogTagsListPath === null) {
|
if (Object.keys(blogTags).length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagsModule: {[tagName: string]: TagModule} = Object.fromEntries(
|
async function createTagsListPage() {
|
||||||
Object.entries(blogTags).map(([, tag]) => {
|
const tagsProp: TagsListItem[] = Object.values(blogTags).map((tag) => ({
|
||||||
const tagModule: TagModule = {
|
label: tag.label,
|
||||||
allTagsPath: blogTagsListPath,
|
|
||||||
name: tag.name,
|
|
||||||
count: tag.items.length,
|
|
||||||
permalink: tag.permalink,
|
permalink: tag.permalink,
|
||||||
};
|
count: tag.items.length,
|
||||||
return [tag.name, tagModule];
|
}));
|
||||||
}),
|
|
||||||
|
const tagsPropPath = await createData(
|
||||||
|
`${docuHash(`${blogTagsListPath}-tags`)}.json`,
|
||||||
|
JSON.stringify(tagsProp, null, 2),
|
||||||
);
|
);
|
||||||
|
|
||||||
async function createTagRoutes(tag: BlogTag): Promise<void> {
|
addRoute({
|
||||||
|
path: blogTagsListPath,
|
||||||
|
component: blogTagsListComponent,
|
||||||
|
exact: true,
|
||||||
|
modules: {
|
||||||
|
sidebar: aliasedSource(sidebarProp),
|
||||||
|
tags: aliasedSource(tagsPropPath),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createTagPostsListPage(tag: BlogTag): Promise<void> {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
tag.pages.map(async (blogPaginated) => {
|
tag.pages.map(async (blogPaginated) => {
|
||||||
const {metadata, items} = blogPaginated;
|
const {metadata, items} = blogPaginated;
|
||||||
const tagsMetadataPath = await createData(
|
const tagProp: TagModule = {
|
||||||
|
label: tag.label,
|
||||||
|
permalink: tag.permalink,
|
||||||
|
allTagsPath: blogTagsListPath,
|
||||||
|
count: tag.items.length,
|
||||||
|
};
|
||||||
|
const tagPropPath = await createData(
|
||||||
`${docuHash(metadata.permalink)}.json`,
|
`${docuHash(metadata.permalink)}.json`,
|
||||||
JSON.stringify(tagsModule[tag.name], null, 2),
|
JSON.stringify(tagProp, null, 2),
|
||||||
);
|
);
|
||||||
|
|
||||||
const listMetadataPath = await createData(
|
const listMetadataPath = await createData(
|
||||||
|
@ -356,7 +373,7 @@ export default async function pluginContentBlog(
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
metadata: aliasedSource(tagsMetadataPath),
|
tag: aliasedSource(tagPropPath),
|
||||||
listMetadata: aliasedSource(listMetadataPath),
|
listMetadata: aliasedSource(listMetadataPath),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -364,25 +381,8 @@ export default async function pluginContentBlog(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(Object.values(blogTags).map(createTagRoutes));
|
await createTagsListPage();
|
||||||
|
await Promise.all(Object.values(blogTags).map(createTagPostsListPage));
|
||||||
// Only create /tags page if there are tags.
|
|
||||||
if (Object.keys(blogTags).length > 0) {
|
|
||||||
const tagsListPath = await createData(
|
|
||||||
`${docuHash(`${blogTagsListPath}-tags`)}.json`,
|
|
||||||
JSON.stringify(tagsModule, null, 2),
|
|
||||||
);
|
|
||||||
|
|
||||||
addRoute({
|
|
||||||
path: blogTagsListPath,
|
|
||||||
component: blogTagsListComponent,
|
|
||||||
exact: true,
|
|
||||||
modules: {
|
|
||||||
sidebar: aliasedSource(sidebarProp),
|
|
||||||
tags: aliasedSource(tagsListPath),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
translateContent({content, translationFiles}) {
|
translateContent({content, translationFiles}) {
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
|
|
||||||
declare module '@docusaurus/plugin-content-blog' {
|
declare module '@docusaurus/plugin-content-blog' {
|
||||||
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
||||||
import type {FrontMatterTag, Tag} from '@docusaurus/utils';
|
import type {FrontMatterTag} from '@docusaurus/utils';
|
||||||
import type {Overwrite} from 'utility-types';
|
import type {Overwrite} from 'utility-types';
|
||||||
|
import type {Tag} from '@docusaurus/types';
|
||||||
|
|
||||||
export type Assets = {
|
export type Assets = {
|
||||||
/**
|
/**
|
||||||
|
@ -406,17 +407,6 @@ declare module '@docusaurus/plugin-content-blog' {
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type TagModule = {
|
|
||||||
/** Permalink of the tag's own page. */
|
|
||||||
permalink: string;
|
|
||||||
/** Name of the tag. */
|
|
||||||
name: string;
|
|
||||||
/** Number of posts with this tag. */
|
|
||||||
count: number;
|
|
||||||
/** The tags list page. */
|
|
||||||
allTagsPath: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type BlogSidebar = {
|
export type BlogSidebar = {
|
||||||
title: string;
|
title: string;
|
||||||
items: {title: string; permalink: string}[];
|
items: {title: string; permalink: string}[];
|
||||||
|
@ -511,28 +501,30 @@ declare module '@theme/BlogListPage' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/BlogTagsListPage' {
|
declare module '@theme/BlogTagsListPage' {
|
||||||
import type {BlogSidebar, TagModule} from '@docusaurus/plugin-content-blog';
|
import type {BlogSidebar} from '@docusaurus/plugin-content-blog';
|
||||||
|
import type {TagsListItem} from '@docusaurus/types';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
/** Blog sidebar. */
|
/** Blog sidebar. */
|
||||||
readonly sidebar: BlogSidebar;
|
readonly sidebar: BlogSidebar;
|
||||||
/** A map from tag names to the full tag module. */
|
/** All tags declared in this blog. */
|
||||||
readonly tags: Readonly<{[tagName: string]: TagModule}>;
|
readonly tags: TagsListItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function BlogTagsListPage(props: Props): JSX.Element;
|
export default function BlogTagsListPage(props: Props): JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/BlogTagsPostsPage' {
|
declare module '@theme/BlogTagsPostsPage' {
|
||||||
import type {BlogSidebar, TagModule} from '@docusaurus/plugin-content-blog';
|
import type {BlogSidebar} from '@docusaurus/plugin-content-blog';
|
||||||
import type {Content} from '@theme/BlogPostPage';
|
import type {Content} from '@theme/BlogPostPage';
|
||||||
import type {Metadata} from '@theme/BlogListPage';
|
import type {Metadata} from '@theme/BlogListPage';
|
||||||
|
import type {TagModule} from '@docusaurus/types';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
/** Blog sidebar. */
|
/** Blog sidebar. */
|
||||||
readonly sidebar: BlogSidebar;
|
readonly sidebar: BlogSidebar;
|
||||||
/** Metadata of this tag. */
|
/** Metadata of this tag. */
|
||||||
readonly metadata: TagModule;
|
readonly tag: TagModule;
|
||||||
/** Looks exactly the same as the posts list page */
|
/** Looks exactly the same as the posts list page */
|
||||||
readonly listMetadata: Metadata;
|
readonly listMetadata: Metadata;
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {BrokenMarkdownLink, ContentPaths} from '@docusaurus/utils';
|
import type {BrokenMarkdownLink, ContentPaths} from '@docusaurus/utils';
|
||||||
|
import type {Tag} from '@docusaurus/types';
|
||||||
import type {BlogPostMetadata} from '@docusaurus/plugin-content-blog';
|
import type {BlogPostMetadata} from '@docusaurus/plugin-content-blog';
|
||||||
import type {Metadata as BlogPaginatedMetadata} from '@theme/BlogListPage';
|
import type {Metadata as BlogPaginatedMetadata} from '@theme/BlogListPage';
|
||||||
|
|
||||||
|
@ -16,22 +17,16 @@ export type BlogContent = {
|
||||||
blogPosts: BlogPost[];
|
blogPosts: BlogPost[];
|
||||||
blogListPaginated: BlogPaginated[];
|
blogListPaginated: BlogPaginated[];
|
||||||
blogTags: BlogTags;
|
blogTags: BlogTags;
|
||||||
blogTagsListPath: string | null;
|
blogTagsListPath: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BlogTags = {
|
export type BlogTags = {
|
||||||
// TODO, the key is the tag slug/permalink
|
[permalink: string]: BlogTag;
|
||||||
// This is due to legacy frontmatter: tags:
|
|
||||||
// [{label: "xyz", permalink: "/1"}, {label: "xyz", permalink: "/2"}]
|
|
||||||
// Soon we should forbid declaring permalink through frontmatter
|
|
||||||
[tagKey: string]: BlogTag;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BlogTag = {
|
export type BlogTag = Tag & {
|
||||||
name: string;
|
|
||||||
/** Blog post permalinks. */
|
/** Blog post permalinks. */
|
||||||
items: string[];
|
items: string[];
|
||||||
permalink: string;
|
|
||||||
pages: BlogPaginated[];
|
pages: BlogPaginated[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -714,9 +714,11 @@ exports[`simple website content: data 1`] = `
|
||||||
}
|
}
|
||||||
}",
|
}",
|
||||||
"tag-docs-tags-tag-1-b3f.json": "{
|
"tag-docs-tags-tag-1-b3f.json": "{
|
||||||
\\"name\\": \\"tag 1\\",
|
\\"label\\": \\"tag 1\\",
|
||||||
\\"permalink\\": \\"/docs/tags/tag-1\\",
|
\\"permalink\\": \\"/docs/tags/tag-1\\",
|
||||||
\\"docs\\": [
|
\\"allTagsPath\\": \\"/docs/tags\\",
|
||||||
|
\\"count\\": 2,
|
||||||
|
\\"items\\": [
|
||||||
{
|
{
|
||||||
\\"id\\": \\"foo/baz\\",
|
\\"id\\": \\"foo/baz\\",
|
||||||
\\"title\\": \\"baz\\",
|
\\"title\\": \\"baz\\",
|
||||||
|
@ -729,48 +731,49 @@ exports[`simple website content: data 1`] = `
|
||||||
\\"description\\": \\"Hi, Endilie here :)\\",
|
\\"description\\": \\"Hi, Endilie here :)\\",
|
||||||
\\"permalink\\": \\"/docs/\\"
|
\\"permalink\\": \\"/docs/\\"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
\\"allTagsPath\\": \\"/docs/tags\\"
|
|
||||||
}",
|
}",
|
||||||
"tag-docs-tags-tag-2-custom-permalink-825.json": "{
|
"tag-docs-tags-tag-2-custom-permalink-825.json": "{
|
||||||
\\"name\\": \\"tag 2\\",
|
\\"label\\": \\"tag 2\\",
|
||||||
\\"permalink\\": \\"/docs/tags/tag2-custom-permalink\\",
|
\\"permalink\\": \\"/docs/tags/tag2-custom-permalink\\",
|
||||||
\\"docs\\": [
|
\\"allTagsPath\\": \\"/docs/tags\\",
|
||||||
|
\\"count\\": 1,
|
||||||
|
\\"items\\": [
|
||||||
{
|
{
|
||||||
\\"id\\": \\"foo/baz\\",
|
\\"id\\": \\"foo/baz\\",
|
||||||
\\"title\\": \\"baz\\",
|
\\"title\\": \\"baz\\",
|
||||||
\\"description\\": \\"Images\\",
|
\\"description\\": \\"Images\\",
|
||||||
\\"permalink\\": \\"/docs/foo/bazSlug.html\\"
|
\\"permalink\\": \\"/docs/foo/bazSlug.html\\"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
\\"allTagsPath\\": \\"/docs/tags\\"
|
|
||||||
}",
|
}",
|
||||||
"tag-docs-tags-tag-3-ab5.json": "{
|
"tag-docs-tags-tag-3-ab5.json": "{
|
||||||
\\"name\\": \\"tag 3\\",
|
\\"label\\": \\"tag 3\\",
|
||||||
\\"permalink\\": \\"/docs/tags/tag-3\\",
|
\\"permalink\\": \\"/docs/tags/tag-3\\",
|
||||||
\\"docs\\": [
|
\\"allTagsPath\\": \\"/docs/tags\\",
|
||||||
|
\\"count\\": 1,
|
||||||
|
\\"items\\": [
|
||||||
{
|
{
|
||||||
\\"id\\": \\"hello\\",
|
\\"id\\": \\"hello\\",
|
||||||
\\"title\\": \\"Hello, World !\\",
|
\\"title\\": \\"Hello, World !\\",
|
||||||
\\"description\\": \\"Hi, Endilie here :)\\",
|
\\"description\\": \\"Hi, Endilie here :)\\",
|
||||||
\\"permalink\\": \\"/docs/\\"
|
\\"permalink\\": \\"/docs/\\"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
\\"allTagsPath\\": \\"/docs/tags\\"
|
|
||||||
}",
|
}",
|
||||||
"tags-list-current-prop-15a.json": "[
|
"tags-list-current-prop-15a.json": "[
|
||||||
{
|
{
|
||||||
\\"name\\": \\"tag 1\\",
|
\\"label\\": \\"tag 1\\",
|
||||||
\\"permalink\\": \\"/docs/tags/tag-1\\",
|
\\"permalink\\": \\"/docs/tags/tag-1\\",
|
||||||
\\"count\\": 2
|
\\"count\\": 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
\\"name\\": \\"tag 2\\",
|
\\"label\\": \\"tag 2\\",
|
||||||
\\"permalink\\": \\"/docs/tags/tag2-custom-permalink\\",
|
\\"permalink\\": \\"/docs/tags/tag2-custom-permalink\\",
|
||||||
\\"count\\": 1
|
\\"count\\": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
\\"name\\": \\"tag 3\\",
|
\\"label\\": \\"tag 3\\",
|
||||||
\\"permalink\\": \\"/docs/tags/tag-3\\",
|
\\"permalink\\": \\"/docs/tags/tag-3\\",
|
||||||
\\"count\\": 1
|
\\"count\\": 1
|
||||||
}
|
}
|
||||||
|
@ -3172,57 +3175,60 @@ exports[`versioned website content: data 1`] = `
|
||||||
}
|
}
|
||||||
}",
|
}",
|
||||||
"tag-docs-next-tags-bar-tag-1-a8f.json": "{
|
"tag-docs-next-tags-bar-tag-1-a8f.json": "{
|
||||||
\\"name\\": \\"barTag 1\\",
|
\\"label\\": \\"barTag 1\\",
|
||||||
\\"permalink\\": \\"/docs/next/tags/bar-tag-1\\",
|
\\"permalink\\": \\"/docs/next/tags/bar-tag-1\\",
|
||||||
\\"docs\\": [
|
\\"allTagsPath\\": \\"/docs/next/tags\\",
|
||||||
|
\\"count\\": 1,
|
||||||
|
\\"items\\": [
|
||||||
{
|
{
|
||||||
\\"id\\": \\"foo/bar\\",
|
\\"id\\": \\"foo/bar\\",
|
||||||
\\"title\\": \\"bar\\",
|
\\"title\\": \\"bar\\",
|
||||||
\\"description\\": \\"This is next version of bar.\\",
|
\\"description\\": \\"This is next version of bar.\\",
|
||||||
\\"permalink\\": \\"/docs/next/foo/barSlug\\"
|
\\"permalink\\": \\"/docs/next/foo/barSlug\\"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
\\"allTagsPath\\": \\"/docs/next/tags\\"
|
|
||||||
}",
|
}",
|
||||||
"tag-docs-next-tags-bar-tag-2-216.json": "{
|
"tag-docs-next-tags-bar-tag-2-216.json": "{
|
||||||
\\"name\\": \\"barTag-2\\",
|
\\"label\\": \\"barTag-2\\",
|
||||||
\\"permalink\\": \\"/docs/next/tags/bar-tag-2\\",
|
\\"permalink\\": \\"/docs/next/tags/bar-tag-2\\",
|
||||||
\\"docs\\": [
|
\\"allTagsPath\\": \\"/docs/next/tags\\",
|
||||||
|
\\"count\\": 1,
|
||||||
|
\\"items\\": [
|
||||||
{
|
{
|
||||||
\\"id\\": \\"foo/bar\\",
|
\\"id\\": \\"foo/bar\\",
|
||||||
\\"title\\": \\"bar\\",
|
\\"title\\": \\"bar\\",
|
||||||
\\"description\\": \\"This is next version of bar.\\",
|
\\"description\\": \\"This is next version of bar.\\",
|
||||||
\\"permalink\\": \\"/docs/next/foo/barSlug\\"
|
\\"permalink\\": \\"/docs/next/foo/barSlug\\"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
\\"allTagsPath\\": \\"/docs/next/tags\\"
|
|
||||||
}",
|
}",
|
||||||
"tag-docs-next-tags-bar-tag-3-permalink-94a.json": "{
|
"tag-docs-next-tags-bar-tag-3-permalink-94a.json": "{
|
||||||
\\"name\\": \\"barTag 3\\",
|
\\"label\\": \\"barTag 3\\",
|
||||||
\\"permalink\\": \\"/docs/next/tags/barTag-3-permalink\\",
|
\\"permalink\\": \\"/docs/next/tags/barTag-3-permalink\\",
|
||||||
\\"docs\\": [
|
\\"allTagsPath\\": \\"/docs/next/tags\\",
|
||||||
|
\\"count\\": 1,
|
||||||
|
\\"items\\": [
|
||||||
{
|
{
|
||||||
\\"id\\": \\"foo/bar\\",
|
\\"id\\": \\"foo/bar\\",
|
||||||
\\"title\\": \\"bar\\",
|
\\"title\\": \\"bar\\",
|
||||||
\\"description\\": \\"This is next version of bar.\\",
|
\\"description\\": \\"This is next version of bar.\\",
|
||||||
\\"permalink\\": \\"/docs/next/foo/barSlug\\"
|
\\"permalink\\": \\"/docs/next/foo/barSlug\\"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
\\"allTagsPath\\": \\"/docs/next/tags\\"
|
|
||||||
}",
|
}",
|
||||||
"tags-list-current-prop-15a.json": "[
|
"tags-list-current-prop-15a.json": "[
|
||||||
{
|
{
|
||||||
\\"name\\": \\"barTag 1\\",
|
\\"label\\": \\"barTag 1\\",
|
||||||
\\"permalink\\": \\"/docs/next/tags/bar-tag-1\\",
|
\\"permalink\\": \\"/docs/next/tags/bar-tag-1\\",
|
||||||
\\"count\\": 1
|
\\"count\\": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
\\"name\\": \\"barTag-2\\",
|
\\"label\\": \\"barTag-2\\",
|
||||||
\\"permalink\\": \\"/docs/next/tags/bar-tag-2\\",
|
\\"permalink\\": \\"/docs/next/tags/bar-tag-2\\",
|
||||||
\\"count\\": 1
|
\\"count\\": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
\\"name\\": \\"barTag 3\\",
|
\\"label\\": \\"barTag 3\\",
|
||||||
\\"permalink\\": \\"/docs/next/tags/barTag-3-permalink\\",
|
\\"permalink\\": \\"/docs/next/tags/barTag-3-permalink\\",
|
||||||
\\"count\\": 1
|
\\"count\\": 1
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,9 +54,10 @@ describe('toTagDocListProp', () => {
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
allTagsPath,
|
allTagsPath,
|
||||||
name: tag.label,
|
count: 2,
|
||||||
|
label: tag.label,
|
||||||
permalink: tag.permalink,
|
permalink: tag.permalink,
|
||||||
docs: [doc3, doc1], // docs sorted by title, ignore "id5" absence
|
items: [doc3, doc1], // docs sorted by title, ignore "id5" absence
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -228,13 +228,13 @@ export default async function pluginContentDocs(
|
||||||
const tagsProp: PropTagsListPage['tags'] = Object.values(
|
const tagsProp: PropTagsListPage['tags'] = Object.values(
|
||||||
versionTags,
|
versionTags,
|
||||||
).map((tagValue) => ({
|
).map((tagValue) => ({
|
||||||
name: tagValue.label,
|
label: tagValue.label,
|
||||||
permalink: tagValue.permalink,
|
permalink: tagValue.permalink,
|
||||||
count: tagValue.docIds.length,
|
count: tagValue.docIds.length,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Only create /tags page if there are tags.
|
// Only create /tags page if there are tags.
|
||||||
if (Object.keys(tagsProp).length > 0) {
|
if (tagsProp.length > 0) {
|
||||||
const tagsPropPath = await createData(
|
const tagsPropPath = await createData(
|
||||||
`${docuHash(`tags-list-${version.versionName}-prop`)}.json`,
|
`${docuHash(`tags-list-${version.versionName}-prop`)}.json`,
|
||||||
JSON.stringify(tagsProp, null, 2),
|
JSON.stringify(tagsProp, null, 2),
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
|
|
||||||
declare module '@docusaurus/plugin-content-docs' {
|
declare module '@docusaurus/plugin-content-docs' {
|
||||||
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
import type {MDXOptions} from '@docusaurus/mdx-loader';
|
||||||
import type {ContentPaths, Tag, FrontMatterTag} from '@docusaurus/utils';
|
import type {ContentPaths, FrontMatterTag} from '@docusaurus/utils';
|
||||||
|
import type {TagsListItem, TagModule, Tag} from '@docusaurus/types';
|
||||||
import type {Required} from 'utility-types';
|
import type {Required} from 'utility-types';
|
||||||
|
|
||||||
export type Assets = {
|
export type Assets = {
|
||||||
|
@ -483,25 +484,14 @@ declare module '@docusaurus/plugin-content-docs' {
|
||||||
export type PropSidebar = import('./sidebars/types').PropSidebar;
|
export type PropSidebar = import('./sidebars/types').PropSidebar;
|
||||||
export type PropSidebars = import('./sidebars/types').PropSidebars;
|
export type PropSidebars = import('./sidebars/types').PropSidebars;
|
||||||
|
|
||||||
export type PropTagDocListDoc = {
|
export type PropTagDocListDoc = Pick<
|
||||||
id: string;
|
DocMetadata,
|
||||||
title: string;
|
'id' | 'title' | 'description' | 'permalink'
|
||||||
description: string;
|
>;
|
||||||
permalink: string;
|
export type PropTagDocList = TagModule & {items: PropTagDocListDoc[]};
|
||||||
};
|
|
||||||
export type PropTagDocList = {
|
|
||||||
allTagsPath: string;
|
|
||||||
name: string; // normalized name/label of the tag
|
|
||||||
permalink: string; // pathname of the tag
|
|
||||||
docs: PropTagDocListDoc[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PropTagsListPage = {
|
export type PropTagsListPage = {
|
||||||
tags: {
|
tags: TagsListItem[];
|
||||||
name: string;
|
|
||||||
permalink: string;
|
|
||||||
count: number;
|
|
||||||
}[];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ export function toTagDocListProp({
|
||||||
}: {
|
}: {
|
||||||
allTagsPath: string;
|
allTagsPath: string;
|
||||||
tag: VersionTag;
|
tag: VersionTag;
|
||||||
docs: Pick<DocMetadata, 'id' | 'title' | 'description' | 'permalink'>[];
|
docs: DocMetadata[];
|
||||||
}): PropTagDocList {
|
}): PropTagDocList {
|
||||||
function toDocListProp(): PropTagDocListDoc[] {
|
function toDocListProp(): PropTagDocListDoc[] {
|
||||||
const list = _.compact(
|
const list = _.compact(
|
||||||
|
@ -154,9 +154,10 @@ export function toTagDocListProp({
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: tag.label,
|
label: tag.label,
|
||||||
permalink: tag.permalink,
|
permalink: tag.permalink,
|
||||||
docs: toDocListProp(),
|
|
||||||
allTagsPath,
|
allTagsPath,
|
||||||
|
count: tag.docIds.length,
|
||||||
|
items: toDocListProp(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,14 @@
|
||||||
/// <reference types="@docusaurus/module-type-aliases" />
|
/// <reference types="@docusaurus/module-type-aliases" />
|
||||||
|
|
||||||
import type {Sidebars} from './sidebars/types';
|
import type {Sidebars} from './sidebars/types';
|
||||||
import type {BrokenMarkdownLink, Tag} from '@docusaurus/utils';
|
import type {BrokenMarkdownLink} from '@docusaurus/utils';
|
||||||
import type {
|
import type {
|
||||||
VersionMetadata,
|
VersionMetadata,
|
||||||
LastUpdateData,
|
LastUpdateData,
|
||||||
DocMetadata,
|
DocMetadata,
|
||||||
CategoryGeneratedIndexMetadata,
|
CategoryGeneratedIndexMetadata,
|
||||||
} from '@docusaurus/plugin-content-docs';
|
} from '@docusaurus/plugin-content-docs';
|
||||||
|
import type {Tag} from '@docusaurus/types';
|
||||||
|
|
||||||
export type DocFile = {
|
export type DocFile = {
|
||||||
contentPath: string; // /!\ may be localized
|
contentPath: string; // /!\ may be localized
|
||||||
|
@ -33,7 +34,7 @@ export type VersionTag = Tag & {
|
||||||
docIds: string[];
|
docIds: string[];
|
||||||
};
|
};
|
||||||
export type VersionTags = {
|
export type VersionTags = {
|
||||||
[key: string]: VersionTag;
|
[permalink: string]: VersionTag;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LoadedVersion = VersionMetadata & {
|
export type LoadedVersion = VersionMetadata & {
|
||||||
|
|
|
@ -1031,7 +1031,7 @@ declare module '@theme/IconExternalLink' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/TagsListByLetter' {
|
declare module '@theme/TagsListByLetter' {
|
||||||
import type {TagsListItem} from '@docusaurus/theme-common';
|
import type {TagsListItem} from '@docusaurus/types';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly tags: readonly TagsListItem[];
|
readonly tags: readonly TagsListItem[];
|
||||||
|
@ -1040,7 +1040,7 @@ declare module '@theme/TagsListByLetter' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/TagsListInline' {
|
declare module '@theme/TagsListInline' {
|
||||||
import type {Tag} from '@docusaurus/utils';
|
import type {Tag} from '@docusaurus/types';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly tags: readonly Tag[];
|
readonly tags: readonly Tag[];
|
||||||
|
@ -1049,7 +1049,7 @@ declare module '@theme/TagsListInline' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/Tag' {
|
declare module '@theme/Tag' {
|
||||||
import type {TagsListItem} from '@docusaurus/theme-common';
|
import type {TagsListItem} from '@docusaurus/types';
|
||||||
import type {Optional} from 'utility-types';
|
import type {Optional} from 'utility-types';
|
||||||
|
|
||||||
export interface Props extends Optional<TagsListItem, 'count'> {}
|
export interface Props extends Optional<TagsListItem, 'count'> {}
|
||||||
|
|
|
@ -19,8 +19,7 @@ import {
|
||||||
import SearchMetadata from '../SearchMetadata';
|
import SearchMetadata from '../SearchMetadata';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
export default function BlogTagsListPage(props: Props): JSX.Element {
|
export default function BlogTagsListPage({tags, sidebar}: Props): JSX.Element {
|
||||||
const {tags, sidebar} = props;
|
|
||||||
const title = translateTagsPageTitle();
|
const title = translateTagsPageTitle();
|
||||||
return (
|
return (
|
||||||
<HtmlClassNameProvider
|
<HtmlClassNameProvider
|
||||||
|
@ -32,7 +31,7 @@ export default function BlogTagsListPage(props: Props): JSX.Element {
|
||||||
<SearchMetadata tag="blog_tags_list" />
|
<SearchMetadata tag="blog_tags_list" />
|
||||||
<BlogLayout sidebar={sidebar}>
|
<BlogLayout sidebar={sidebar}>
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
<TagsListByLetter tags={Object.values(tags)} />
|
<TagsListByLetter tags={tags} />
|
||||||
</BlogLayout>
|
</BlogLayout>
|
||||||
</HtmlClassNameProvider>
|
</HtmlClassNameProvider>
|
||||||
);
|
);
|
||||||
|
|
|
@ -40,9 +40,12 @@ function useBlogPostsPlural() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function BlogTagsPostsPage(props: Props): JSX.Element {
|
export default function BlogTagsPostsPage({
|
||||||
const {metadata, items, sidebar, listMetadata} = props;
|
tag,
|
||||||
const {allTagsPath, name: tagName, count} = metadata;
|
items,
|
||||||
|
sidebar,
|
||||||
|
listMetadata,
|
||||||
|
}: Props): JSX.Element {
|
||||||
const blogPostsPlural = useBlogPostsPlural();
|
const blogPostsPlural = useBlogPostsPlural();
|
||||||
const title = translate(
|
const title = translate(
|
||||||
{
|
{
|
||||||
|
@ -50,7 +53,7 @@ export default function BlogTagsPostsPage(props: Props): JSX.Element {
|
||||||
description: 'The title of the page for a blog tag',
|
description: 'The title of the page for a blog tag',
|
||||||
message: '{nPosts} tagged with "{tagName}"',
|
message: '{nPosts} tagged with "{tagName}"',
|
||||||
},
|
},
|
||||||
{nPosts: blogPostsPlural(count), tagName},
|
{nPosts: blogPostsPlural(tag.count), tagName: tag.label},
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -65,7 +68,7 @@ export default function BlogTagsPostsPage(props: Props): JSX.Element {
|
||||||
<header className="margin-bottom--xl">
|
<header className="margin-bottom--xl">
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
|
|
||||||
<Link href={allTagsPath}>
|
<Link href={tag.allTagsPath}>
|
||||||
<Translate
|
<Translate
|
||||||
id="theme.tags.tagsPageLink"
|
id="theme.tags.tagsPageLink"
|
||||||
description="The label of the link targeting the tag list page">
|
description="The label of the link targeting the tag list page">
|
||||||
|
|
|
@ -15,7 +15,6 @@ import {
|
||||||
ThemeClassNames,
|
ThemeClassNames,
|
||||||
usePluralForm,
|
usePluralForm,
|
||||||
} from '@docusaurus/theme-common';
|
} from '@docusaurus/theme-common';
|
||||||
import type {PropTagDocListDoc} from '@docusaurus/plugin-content-docs';
|
|
||||||
import Translate, {translate} from '@docusaurus/Translate';
|
import Translate, {translate} from '@docusaurus/Translate';
|
||||||
import type {Props} from '@theme/DocTagDocListPage';
|
import type {Props} from '@theme/DocTagDocListPage';
|
||||||
import SearchMetadata from '@theme/SearchMetadata';
|
import SearchMetadata from '@theme/SearchMetadata';
|
||||||
|
@ -39,7 +38,7 @@ function useNDocsTaggedPlural() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DocItem({doc}: {doc: PropTagDocListDoc}): JSX.Element {
|
function DocItem({doc}: {doc: Props['tag']['items'][number]}): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<article className="margin-vert--lg">
|
<article className="margin-vert--lg">
|
||||||
<Link to={doc.permalink}>
|
<Link to={doc.permalink}>
|
||||||
|
@ -58,7 +57,7 @@ export default function DocTagDocListPage({tag}: Props): JSX.Element {
|
||||||
description: 'The title of the page for a docs tag',
|
description: 'The title of the page for a docs tag',
|
||||||
message: '{nDocsTagged} with "{tagName}"',
|
message: '{nDocsTagged} with "{tagName}"',
|
||||||
},
|
},
|
||||||
{nDocsTagged: nDocsTaggedPlural(tag.docs.length), tagName: tag.name},
|
{nDocsTagged: nDocsTaggedPlural(tag.count), tagName: tag.label},
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -84,7 +83,7 @@ export default function DocTagDocListPage({tag}: Props): JSX.Element {
|
||||||
</Link>
|
</Link>
|
||||||
</header>
|
</header>
|
||||||
<section className="margin-vert--lg">
|
<section className="margin-vert--lg">
|
||||||
{tag.docs.map((doc) => (
|
{tag.items.map((doc) => (
|
||||||
<DocItem key={doc.id} doc={doc} />
|
<DocItem key={doc.id} doc={doc} />
|
||||||
))}
|
))}
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -12,9 +12,7 @@ import type {Props} from '@theme/Tag';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
export default function Tag(props: Props): JSX.Element {
|
export default function Tag({permalink, label, count}: Props): JSX.Element {
|
||||||
const {permalink, name, count} = props;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
href={permalink}
|
href={permalink}
|
||||||
|
@ -22,7 +20,7 @@ export default function Tag(props: Props): JSX.Element {
|
||||||
styles.tag,
|
styles.tag,
|
||||||
count ? styles.tagWithCount : styles.tagRegular,
|
count ? styles.tagWithCount : styles.tagRegular,
|
||||||
)}>
|
)}>
|
||||||
{name}
|
{label}
|
||||||
{count && <span>{count}</span>}
|
{count && <span>{count}</span>}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|
|
@ -26,7 +26,7 @@ export default function TagsListInline({tags}: Props): JSX.Element {
|
||||||
<ul className={clsx(styles.tags, 'padding--none', 'margin-left--sm')}>
|
<ul className={clsx(styles.tags, 'padding--none', 'margin-left--sm')}>
|
||||||
{tags.map(({label, permalink: tagPermalink}) => (
|
{tags.map(({label, permalink: tagPermalink}) => (
|
||||||
<li key={tagPermalink} className={styles.tag}>
|
<li key={tagPermalink} className={styles.tag}>
|
||||||
<Tag name={label} permalink={tagPermalink} />
|
<Tag label={label} permalink={tagPermalink} />
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -86,7 +86,6 @@ export {
|
||||||
translateTagsPageTitle,
|
translateTagsPageTitle,
|
||||||
listTagsByLetters,
|
listTagsByLetters,
|
||||||
type TagLetterEntry,
|
type TagLetterEntry,
|
||||||
type TagsListItem,
|
|
||||||
} from './utils/tagsUtils';
|
} from './utils/tagsUtils';
|
||||||
|
|
||||||
export {useHistoryPopHandler} from './utils/historyUtils';
|
export {useHistoryPopHandler} from './utils/historyUtils';
|
||||||
|
|
|
@ -15,32 +15,32 @@ describe('listTagsByLetters', () => {
|
||||||
|
|
||||||
it('creates letters list', () => {
|
it('creates letters list', () => {
|
||||||
const tag1: Tag = {
|
const tag1: Tag = {
|
||||||
name: 'tag1',
|
label: 'tag1',
|
||||||
permalink: '/tag1',
|
permalink: '/tag1',
|
||||||
count: 1,
|
count: 1,
|
||||||
};
|
};
|
||||||
const tag2: Tag = {
|
const tag2: Tag = {
|
||||||
name: 'Tag2',
|
label: 'Tag2',
|
||||||
permalink: '/tag2',
|
permalink: '/tag2',
|
||||||
count: 11,
|
count: 11,
|
||||||
};
|
};
|
||||||
const tagZxy: Tag = {
|
const tagZxy: Tag = {
|
||||||
name: 'zxy',
|
label: 'zxy',
|
||||||
permalink: '/zxy',
|
permalink: '/zxy',
|
||||||
count: 987,
|
count: 987,
|
||||||
};
|
};
|
||||||
const tagAbc: Tag = {
|
const tagAbc: Tag = {
|
||||||
name: 'Abc',
|
label: 'Abc',
|
||||||
permalink: '/abc',
|
permalink: '/abc',
|
||||||
count: 123,
|
count: 123,
|
||||||
};
|
};
|
||||||
const tagDef: Tag = {
|
const tagDef: Tag = {
|
||||||
name: 'def',
|
label: 'def',
|
||||||
permalink: '/def',
|
permalink: '/def',
|
||||||
count: 1,
|
count: 1,
|
||||||
};
|
};
|
||||||
const tagAaa: Tag = {
|
const tagAaa: Tag = {
|
||||||
name: 'aaa',
|
label: 'aaa',
|
||||||
permalink: '/aaa',
|
permalink: '/aaa',
|
||||||
count: 10,
|
count: 10,
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {translate} from '@docusaurus/Translate';
|
import {translate} from '@docusaurus/Translate';
|
||||||
|
import type {TagsListItem} from '@docusaurus/types';
|
||||||
|
|
||||||
export const translateTagsPageTitle = (): string =>
|
export const translateTagsPageTitle = (): string =>
|
||||||
translate({
|
translate({
|
||||||
|
@ -14,13 +15,7 @@ export const translateTagsPageTitle = (): string =>
|
||||||
description: 'The title of the tag list page',
|
description: 'The title of the tag list page',
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TagsListItem = Readonly<{
|
export type TagLetterEntry = {letter: string; tags: TagsListItem[]};
|
||||||
name: string;
|
|
||||||
permalink: string;
|
|
||||||
count: number;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type TagLetterEntry = Readonly<{letter: string; tags: TagsListItem[]}>;
|
|
||||||
|
|
||||||
function getTagLetter(tag: string): string {
|
function getTagLetter(tag: string): string {
|
||||||
return tag[0]!.toUpperCase();
|
return tag[0]!.toUpperCase();
|
||||||
|
@ -35,7 +30,7 @@ export function listTagsByLetters(
|
||||||
): TagLetterEntry[] {
|
): TagLetterEntry[] {
|
||||||
const groups: {[initial: string]: TagsListItem[]} = {};
|
const groups: {[initial: string]: TagsListItem[]} = {};
|
||||||
Object.values(tags).forEach((tag) => {
|
Object.values(tags).forEach((tag) => {
|
||||||
const initial = getTagLetter(tag.name);
|
const initial = getTagLetter(tag.label);
|
||||||
groups[initial] ??= [];
|
groups[initial] ??= [];
|
||||||
groups[initial]!.push(tag);
|
groups[initial]!.push(tag);
|
||||||
});
|
});
|
||||||
|
@ -47,7 +42,7 @@ export function listTagsByLetters(
|
||||||
.map(([letter, letterTags]) => {
|
.map(([letter, letterTags]) => {
|
||||||
// Sort tags inside a letter
|
// Sort tags inside a letter
|
||||||
const sortedTags = letterTags.sort((tag1, tag2) =>
|
const sortedTags = letterTags.sort((tag1, tag2) =>
|
||||||
tag1.name.localeCompare(tag2.name),
|
tag1.label.localeCompare(tag2.label),
|
||||||
);
|
);
|
||||||
return {letter, tags: sortedTags};
|
return {letter, tags: sortedTags};
|
||||||
})
|
})
|
||||||
|
|
19
packages/docusaurus-types/src/index.d.ts
vendored
19
packages/docusaurus-types/src/index.d.ts
vendored
|
@ -594,3 +594,22 @@ export type ClientModule = {
|
||||||
}) => void;
|
}) => void;
|
||||||
onRouteUpdateDelayed?: (args: {location: Location}) => void;
|
onRouteUpdateDelayed?: (args: {location: Location}) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** What the user configures. */
|
||||||
|
export type Tag = {
|
||||||
|
label: string;
|
||||||
|
/** Permalink to this tag's page, without the `/tags/` base path. */
|
||||||
|
permalink: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** What the tags list page should know about each tag. */
|
||||||
|
export type TagsListItem = Tag & {
|
||||||
|
/** Number of posts/docs with this tag. */
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** What the tag's own page should know about the tag. */
|
||||||
|
export type TagModule = TagsListItem & {
|
||||||
|
/** The tags list page's permalink. */
|
||||||
|
allTagsPath: string;
|
||||||
|
};
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import Joi from './Joi';
|
import Joi from './Joi';
|
||||||
import {isValidPathname, DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
import {isValidPathname, DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
|
||||||
import type {Tag} from '@docusaurus/utils';
|
import type {Tag} from '@docusaurus/types';
|
||||||
import {JoiFrontMatter} from './JoiFrontMatter';
|
import {JoiFrontMatter} from './JoiFrontMatter';
|
||||||
|
|
||||||
export const PluginIdSchema = Joi.string()
|
export const PluginIdSchema = Joi.string()
|
||||||
|
|
|
@ -56,7 +56,6 @@ export {
|
||||||
buildSshUrl,
|
buildSshUrl,
|
||||||
} from './urlUtils';
|
} from './urlUtils';
|
||||||
export {
|
export {
|
||||||
type Tag,
|
|
||||||
type FrontMatterTag,
|
type FrontMatterTag,
|
||||||
normalizeFrontMatterTags,
|
normalizeFrontMatterTags,
|
||||||
groupTaggedItems,
|
groupTaggedItems,
|
||||||
|
|
|
@ -7,12 +7,7 @@
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import {normalizeUrl} from './urlUtils';
|
import {normalizeUrl} from './urlUtils';
|
||||||
|
import type {Tag} from '@docusaurus/types';
|
||||||
export type Tag = {
|
|
||||||
label: string;
|
|
||||||
/** Permalink to this tag's page, without the `/tags/` base path. */
|
|
||||||
permalink: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type FrontMatterTag = string | Tag;
|
export type FrontMatterTag = string | Tag;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue