Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: doc tags (same as blog tags) #3646

Merged
merged 35 commits into from
Aug 19, 2021
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5b00807
[v2] tags to doc, same as tags to blog - [IN PROGRESS]
isaac-philip Oct 24, 2020
f618a72
docs: make tags list page work
slorber Oct 28, 2020
4949fb6
temp: disable onBrokenLinks
slorber Oct 28, 2020
947b034
theme bootstrap: create DocTagsListPage
slorber Oct 29, 2020
bc56aba
DocTagsPage added and functionality too
isaac-philip May 27, 2021
59212bb
Added all Docs Tags Link
isaac-philip May 29, 2021
7d454b4
Merge branch 'master' into docs_get_tags
slorber Aug 17, 2021
9c7773d
add some shared tag utils
slorber Aug 17, 2021
53337bf
move tag tests to _dogfooding
slorber Aug 17, 2021
5d11d6e
fix type
slorber Aug 17, 2021
89262c2
fix some tests
slorber Aug 17, 2021
636d82b
fix blog test
slorber Aug 17, 2021
dc897b6
refactor blog post tags handling
slorber Aug 17, 2021
975a1ae
Merge branch 'main' into docs_get_tags
slorber Aug 18, 2021
a31b864
better yaml tag examples
slorber Aug 18, 2021
c049e7b
better dogfood md files
slorber Aug 18, 2021
de11d50
refactor and factorize theme tag components
slorber Aug 18, 2021
3c358b4
finish DocTagDocListPage
slorber Aug 18, 2021
d6bbbb4
Extract DocItemFooter + add inline tag list
slorber Aug 18, 2021
7075b98
minor fix
slorber Aug 18, 2021
ea612f3
better typings
slorber Aug 18, 2021
7bc7473
fix versions.test.ts tests
slorber Aug 18, 2021
0a6d771
add tests for doc tags
slorber Aug 18, 2021
2c21138
fix tests
slorber Aug 18, 2021
134b896
test toTagDocListProp
slorber Aug 18, 2021
724b27d
move shared theme code to tagUtils
slorber Aug 18, 2021
51fd4ab
Add new theme translation keys
slorber Aug 18, 2021
1708882
move common theme code to tagUtils + add tests
slorber Aug 18, 2021
c3a1c76
update-code-translations should handle theme-common
slorber Aug 18, 2021
50b8c78
update french translation
slorber Aug 18, 2021
b3231ee
revert add translation
slorber Aug 18, 2021
15f3a44
fix pluralization problem in theme.docs.tagDocListPageTitle
slorber Aug 18, 2021
3171b83
add theme component configuration options
slorber Aug 18, 2021
f460912
add more tags tests
slorber Aug 18, 2021
58367bb
add documentation for docs tagging
slorber Aug 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 4 additions & 15 deletions packages/docusaurus-plugin-content-blog/src/blogFrontMatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ import {
JoiFrontMatter as Joi, // Custom instance for frontmatter
URISchema,
validateFrontMatter,
FrontMatterTagsSchema,
} from '@docusaurus/utils-validation';
import {Tag} from './types';
import type {FrontMatterTag} from '@docusaurus/utils';

export type BlogPostFrontMatter = {
/* eslint-disable camelcase */
id?: string;
title?: string;
description?: string;
tags?: (string | Tag)[];
tags?: FrontMatterTag[];
slug?: string;
draft?: boolean;
date?: Date | string; // Yaml automagically convert some string patterns as Date, but not all
Expand All @@ -38,23 +39,11 @@ export type BlogPostFrontMatter = {
/* 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>({
id: Joi.string(),
title: Joi.string().allow(''),
description: Joi.string().allow(''),
tags: Joi.array().items(BlogTagSchema),
tags: FrontMatterTagsSchema,
draft: Joi.boolean(),
date: Joi.date().raw(),

Expand Down
5 changes: 4 additions & 1 deletion packages/docusaurus-plugin-content-blog/src/blogUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
posixPath,
replaceMarkdownLinks,
Globby,
normalizeFrontMatterTags,
} from '@docusaurus/utils';
import {LoadContext} from '@docusaurus/types';
import {validateBlogPostFrontMatter} from './blogFrontMatter';
Expand Down Expand Up @@ -240,6 +241,8 @@ async function processBlogSourceFile(
return undefined;
}

const tagsBasePath = normalizeUrl([baseUrl, options.routeBasePath, 'tags']); // make this configurable?

return {
id: frontMatter.slug ?? title,
metadata: {
Expand All @@ -250,7 +253,7 @@ async function processBlogSourceFile(
description,
date,
formattedDate,
tags: frontMatter.tags ?? [],
tags: normalizeFrontMatterTags(tagsBasePath, frontMatter.tags),
readingTime: showReadingTime ? readingTime(content).minutes : undefined,
truncated: truncateMarker?.test(content) || false,
},
Expand Down
65 changes: 23 additions & 42 deletions packages/docusaurus-plugin-content-blog/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ import {
posixPath,
addTrailingPathSeparator,
createAbsoluteFilePathMatcher,
groupTaggedItems,
} from '@docusaurus/utils';
import {
STATIC_DIR_NAME,
DEFAULT_PLUGIN_ID,
} from '@docusaurus/core/lib/constants';
import {flatten, take, kebabCase} from 'lodash';
import {flatten, take, mapValues} from 'lodash';

import {
PluginOptions,
Expand Down Expand Up @@ -65,7 +66,7 @@ export default function pluginContentBlog(

const {
siteDir,
siteConfig: {onBrokenMarkdownLinks},
siteConfig: {onBrokenMarkdownLinks, baseUrl},
generatedFilesDir,
i18n: {currentLocale},
} = context;
Expand Down Expand Up @@ -151,17 +152,14 @@ export default function pluginContentBlog(
const postsPerPage =
postsPerPageOption === 'ALL' ? totalCount : postsPerPageOption;
const numberOfPages = Math.ceil(totalCount / postsPerPage);
const {
siteConfig: {baseUrl = ''},
} = context;
const basePageUrl = normalizeUrl([baseUrl, routeBasePath]);
const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);

const blogListPaginated: BlogPaginated[] = [];

function blogPaginationPermalink(page: number) {
return page > 0
? normalizeUrl([basePageUrl, `page/${page + 1}`])
: basePageUrl;
? normalizeUrl([baseBlogUrl, `page/${page + 1}`])
: baseBlogUrl;
}

for (let page = 0; page < numberOfPages; page += 1) {
Expand All @@ -186,41 +184,25 @@ export default function pluginContentBlog(
});
}

const blogTags: BlogTags = {};
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;
}
// Legacy conversion layer, can be refactored
function getBlogPostTags(): BlogTags {
const blogPostsByTag = groupTaggedItems(
blogPosts,
(blogPost) => blogPost.metadata.tags,
);

// eslint-disable-next-line no-param-reassign
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;
return mapValues(blogPostsByTag, (blogPostGroup) => {
return {
name: blogPostGroup.tag.label,
items: blogPostGroup.items.map((item) => item.id),
permalink: blogPostGroup.tag.permalink,
};
});
});
}

const blogTags: BlogTags = getBlogPostTags();

const tagsPath = normalizeUrl([baseBlogUrl, 'tags']);

const blogTagsListPath =
Object.keys(blogTags).length > 0 ? tagsPath : null;
Expand Down Expand Up @@ -535,7 +517,6 @@ export default function pluginContentBlog(
const feedTypes = options.feedOptions.type;
const {
siteConfig: {title},
baseUrl,
} = context;
const feedsConfig = {
rss: {
Expand Down
10 changes: 3 additions & 7 deletions packages/docusaurus-plugin-content-blog/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
*/

import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader';
import {
import type {Tag} from '@docusaurus/utils';
import type {
BrokenMarkdownLink,
ContentPaths,
} from '@docusaurus/utils/lib/markdownLinks';
Expand Down Expand Up @@ -96,7 +97,7 @@ export interface MetaData {
description: string;
date: Date;
formattedDate: string;
tags: (Tag | string)[];
tags: Tag[];
title: string;
readingTime?: number;
prevItem?: Paginator;
Expand All @@ -110,11 +111,6 @@ export interface Paginator {
permalink: string;
}

export interface Tag {
label: string;
permalink: string;
}

export interface BlogItemsToMetadata {
[key: string]: MetaData;
}
Expand Down
1 change: 1 addition & 0 deletions packages/docusaurus-plugin-content-docs/src/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ function doProcessDocMetadata({
slug: docSlug,
permalink,
editUrl: customEditURL !== undefined ? customEditURL : getDocEditUrl(),
tags: frontMatter.tags, // TODO normalize here
version: versionMetadata.versionName,
lastUpdatedBy: lastUpdate.lastUpdatedBy,
lastUpdatedAt: lastUpdate.lastUpdatedAt,
Expand Down
64 changes: 64 additions & 0 deletions packages/docusaurus-plugin-content-docs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
LoadedVersion,
DocFile,
DocsMarkdownOption,
VersionTag,
} from './types';
import {RuleSetRule} from 'webpack';
import {cliDocsVersionCommand} from './cli';
Expand All @@ -50,6 +51,7 @@ import {
} from './translations';
import {CategoryMetadataFilenamePattern} from './sidebarItemsGenerator';
import chalk from 'chalk';
import {getVersionTags} from './tags';

export default function pluginContentDocs(
context: LoadContext,
Expand Down Expand Up @@ -246,10 +248,16 @@ export default function pluginContentDocs(
}
}

const tags = getVersionTags({
docs,
tagsPath: versionMetadata.tagsPath,
});

return {
...versionMetadata,
mainDocId: getMainDoc().unversionedId,
sidebars,
tags,
docs: docs.map(addNavData),
};
}
Expand Down Expand Up @@ -314,9 +322,65 @@ export default function pluginContentDocs(
return routes.sort((a, b) => a.path.localeCompare(b.path));
};

async function createVersionTagsRoutes(loadedVersion: LoadedVersion) {
async function createTagsListRoute() {
const tagsProp = mapValues(loadedVersion.tags, (tagValue) => ({
name: tagValue.name,
permalink: tagValue.permalink,
count: tagValue.docIds.length,
}));
console.log(`version tags info, ${JSON.stringify(loadedVersion)}`);
const tagsPropPath = await createData(
`${docuHash(`tags-list-${loadedVersion.versionName}-prop`)}.json`,
JSON.stringify(tagsProp, null, 2),
);
addRoute({
path: loadedVersion.tagsPath,
exact: true,
component: '@theme/DocTagsListPage',
slorber marked this conversation as resolved.
Show resolved Hide resolved
modules: {
tags: aliasedSource(tagsPropPath),
slorber marked this conversation as resolved.
Show resolved Hide resolved
},
});
}

async function createTagPage(tag: VersionTag) {
/**
* To create a page per Tag for relevant Docs
*/
// TODO
console.log(`todo createTagPage for tag=${tag.name}`);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: do something similar to create one page per tag

console.log(
`tags information is, = ${JSON.stringify(loadedVersion.tags)}`,
);

const copiedTag = JSON.parse(JSON.stringify(tag));
copiedTag.allTagsPath = loadedVersion.tagsPath;

const tagsPath = await createData(
`${docuHash(`${tag.permalink}`)}.json`,
JSON.stringify(copiedTag, null, 2),
);

addRoute({
path: tag.permalink,
component: '@theme/DocTagsPage',
exact: true,
modules: {
tag: aliasedSource(tagsPath),
},
});
}

await createTagsListRoute();
await Promise.all(Object.values(loadedVersion.tags).map(createTagPage));
}

async function doCreateVersionRoutes(
loadedVersion: LoadedVersion,
): Promise<void> {
await createVersionTagsRoutes(loadedVersion);

const versionMetadata = toVersionMetadataProp(pluginId, loadedVersion);
const versionMetadataPropPath = await createData(
`${docuHash(
Expand Down
47 changes: 47 additions & 0 deletions packages/docusaurus-plugin-content-docs/src/tags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* 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 '@docusaurus/utils';
import {VersionTags, DocMetadata} from './types';
import {kebabCase} from 'lodash';

function normalizeTag(tag: string) {
return kebabCase(tag);
}

export function getVersionTags({
tagsPath,
docs,
}: {
tagsPath: string;
docs: DocMetadata[];
}): VersionTags {
const versionTags: VersionTags = {};

function initTagData(tag: string) {
return {
// Will only use the name of the first occurrence of the tag
name: tag.toLowerCase(),
permalink: normalizeUrl([tagsPath, normalizeTag(tag)]),
docIds: [],
};
}

docs.forEach((doc) => {
const tags: string[] = (doc.tags ?? []) as any; // TODO BAD, temporary
tags.forEach((tag) => {
const normalizedTag = normalizeTag(tag);
// init data for a tag the first time we see it
if (!versionTags[normalizedTag]) {
versionTags[normalizedTag] = initTagData(tag);
}
versionTags[normalizedTag].docIds.push(doc.id);
});
});

return versionTags;
}
slorber marked this conversation as resolved.
Show resolved Hide resolved
Loading