From fd270bdceb3147bca72b43aeaf45111f007a49a7 Mon Sep 17 00:00:00 2001 From: Yangshun Tay Date: Mon, 13 May 2019 10:14:44 -0700 Subject: [PATCH] feat(v2): blog tags (#1453) * feat(v2): blog tags * feat(v2): blog tags --- .../src/index.js | 100 +++++++++++++++++- .../src/theme/BlogTagsListPage/index.js | 69 ++++++++++++ .../src/theme/BlogTagsPostsPage/index.js | 46 ++++++++ .../blog/2017-12-14-introducing-docusaurus.md | 1 + ...0-How-I-Converted-Profilo-To-Docusaurus.md | 1 + .../blog/2018-09-11-Towards-Docusaurus-2.md | 3 +- .../2018-12-14-Happy-First-Birthday-Slash.md | 1 + 7 files changed, 218 insertions(+), 3 deletions(-) create mode 100644 packages/docusaurus-plugin-content-blog/src/theme/BlogTagsListPage/index.js create mode 100644 packages/docusaurus-plugin-content-blog/src/theme/BlogTagsPostsPage/index.js diff --git a/packages/docusaurus-plugin-content-blog/src/index.js b/packages/docusaurus-plugin-content-blog/src/index.js index 25f377c5e9..069d2b143d 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.js +++ b/packages/docusaurus-plugin-content-blog/src/index.js @@ -26,6 +26,8 @@ const DEFAULT_OPTIONS = { postsPerPage: 10, // How many posts per page. blogListComponent: '@theme/BlogListPage', blogPostComponent: '@theme/BlogPostPage', + blogTagsListComponent: '@theme/BlogTagsListPage', + blogTagsPostsComponent: '@theme/BlogTagsPostsPage', }; class DocusaurusPluginContentBlog { @@ -87,6 +89,7 @@ class DocusaurusPluginContentBlog { source, description: frontMatter.description || excerpt, date, + tags: frontMatter.tags, title: frontMatter.title || blogFileName, }, }); @@ -126,16 +129,39 @@ class DocusaurusPluginContentBlog { }); } + const blogTags = {}; + blogPosts.forEach(blogPost => { + const {tags} = blogPost.metadata; + if (!tags || tags.length === 0) { + return; + } + + tags.forEach(tag => { + const normalizedTag = tag.toLowerCase(); + if (!blogTags[normalizedTag]) { + blogTags[normalizedTag] = []; + } + blogTags[normalizedTag].push(blogPost.id); + }); + }); + return { blogPosts, blogListPaginated, + blogTags, }; } async contentLoaded({content: blogContents, actions}) { - const {blogListComponent, blogPostComponent} = this.options; + const { + blogListComponent, + blogPostComponent, + blogTagsListComponent, + blogTagsPostsComponent, + } = this.options; + const {addRoute, createData} = actions; - const {blogPosts, blogListPaginated} = blogContents; + const {blogPosts, blogListPaginated, blogTags} = blogContents; const blogItemsToModules = {}; // Create routes for blog entries. @@ -213,6 +239,76 @@ class DocusaurusPluginContentBlog { }); }), ); + + // Tags. + const {routeBasePath} = this.options; + const { + siteConfig: {baseUrl}, + } = this.context; + + const basePageUrl = normalizeUrl([baseUrl, routeBasePath]); + const tagsPath = normalizeUrl([basePageUrl, 'tags']); + const tagsModule = {}; + + await Promise.all( + Object.keys(blogTags).map(async tag => { + const permalink = normalizeUrl([tagsPath, tag]); + const postIDs = blogTags[tag]; + tagsModule[tag] = { + count: postIDs.length, + permalink, + }; + + const tagsMetadataPath = await createData( + `${docuHash(permalink)}.json`, + JSON.stringify( + { + tag, + }, + null, + 2, + ), + ); + + addRoute({ + path: permalink, + component: blogTagsPostsComponent, + exact: true, + modules: { + items: postIDs.map(postID => { + const {metadata: postMetadata, metadataPath} = blogItemsToModules[ + postID + ]; + return { + content: { + __import: true, + path: postMetadata.source, + query: { + truncated: true, + }, + }, + metadata: metadataPath, + }; + }), + metadata: tagsMetadataPath, + }, + }); + }), + ); + + const tagsListPath = await createData( + `${docuHash(`${tagsPath}-tags`)}.json`, + JSON.stringify(tagsModule, null, 2), + ); + + addRoute({ + path: tagsPath, + component: blogTagsListComponent, + exact: true, + modules: { + tags: tagsListPath, + }, + }); } getThemePath() { diff --git a/packages/docusaurus-plugin-content-blog/src/theme/BlogTagsListPage/index.js b/packages/docusaurus-plugin-content-blog/src/theme/BlogTagsListPage/index.js new file mode 100644 index 0000000000..a083e7b8d8 --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/theme/BlogTagsListPage/index.js @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * 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'; // eslint-disable-line +import Link from '@docusaurus/Link'; + +const CHARS_IN_ALPHABET = 26; +const ASCII_LOWERCASE_A = 97; + +function BlogTagsListPage(props) { + const {tags} = props; + + const tagsList = Array(CHARS_IN_ALPHABET) + .fill(null) + .map(() => []); + const allTags = Object.keys(tags).sort(); + + allTags.forEach(tag => { + const firstLetter = tag.charCodeAt(0); + tagsList[firstLetter - ASCII_LOWERCASE_A].push(tag); + }); + + const tagsSection = tagsList + .map((tagsForLetter, index) => { + if (tagsForLetter.length === 0) { + return null; + } + const letter = String.fromCharCode( + ASCII_LOWERCASE_A + index, + ).toUpperCase(); + + return ( +
+

{letter}

+ {tagsForLetter.map(tag => ( + + {tag} ({tags[tag].count}) + + ))} +
+
+ ); + }) + .filter(item => item != null); + + return ( + +
+
+
+

Tags

+
{tagsSection}
+
+
+
+
+ ); +} + +export default BlogTagsListPage; diff --git a/packages/docusaurus-plugin-content-blog/src/theme/BlogTagsPostsPage/index.js b/packages/docusaurus-plugin-content-blog/src/theme/BlogTagsPostsPage/index.js new file mode 100644 index 0000000000..5ab4f30f50 --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/theme/BlogTagsPostsPage/index.js @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * 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'; // eslint-disable-line +import BlogPostItem from '@theme/BlogPostItem'; + +function BlogTagsPostPage(props) { + const {metadata, items} = props; + const {tag} = metadata; + + return ( + +
+
+
+

+ {items.length} post(s) tagged with "{tag}" +

+
+ {items.map( + ({content: BlogPostContent, metadata: blogPostMetadata}) => ( +
+ + + +
+ ), + )} +
+
+
+
+
+ ); +} + +export default BlogTagsPostPage; diff --git a/website-1.x/blog/2017-12-14-introducing-docusaurus.md b/website-1.x/blog/2017-12-14-introducing-docusaurus.md index d60b78be7a..d8231a159e 100644 --- a/website-1.x/blog/2017-12-14-introducing-docusaurus.md +++ b/website-1.x/blog/2017-12-14-introducing-docusaurus.md @@ -4,6 +4,7 @@ author: Joel Marcey authorURL: http://twitter.com/JoelMarcey authorFBID: 611217057 authorTwitter: JoelMarcey +tags: [birth] --- ![Introducing Slash](/img/slash-introducing.svg) diff --git a/website-1.x/blog/2018-04-30-How-I-Converted-Profilo-To-Docusaurus.md b/website-1.x/blog/2018-04-30-How-I-Converted-Profilo-To-Docusaurus.md index 52e4f7c869..fc92dd0088 100644 --- a/website-1.x/blog/2018-04-30-How-I-Converted-Profilo-To-Docusaurus.md +++ b/website-1.x/blog/2018-04-30-How-I-Converted-Profilo-To-Docusaurus.md @@ -4,6 +4,7 @@ author: Christine Abernathy authorURL: http://twitter.com/abernathyca authorFBID: 1424840234 authorTwitter: abernathyca +tags: [profilo, adoption] --- > *“Joel and I were discussing having a website and how it would have been great to launch with it. So I challenged myself to add Docusaurus support. It took just over an hour and a half. I'm going to send you a PR with the addition so you can take a look and see if you like it. Your workflow for adding docs wouldn't be much different from editing those markdown files.”* diff --git a/website-1.x/blog/2018-09-11-Towards-Docusaurus-2.md b/website-1.x/blog/2018-09-11-Towards-Docusaurus-2.md index ac74ea3f40..00893f3d9c 100644 --- a/website-1.x/blog/2018-09-11-Towards-Docusaurus-2.md +++ b/website-1.x/blog/2018-09-11-Towards-Docusaurus-2.md @@ -5,6 +5,7 @@ authorTitle: Maintainer of Docusaurus authorURL: https://github.com/endiliey authorImageURL: https://avatars1.githubusercontent.com/u/17883920?s=460&v=4 authorTwitter: endiliey +tags: [new, adoption] --- Docusaurus was [officially announced](https://docusaurus.io/blog/2017/12/14/introducing-docusaurus) over nine months ago as a way to easily build open source documentation websites. Since then, it has amassed over 8,600 GitHub Stars, and is used by many popular open source projects such as [React Native](https://facebook.github.io/react-native/), [Babel](https://babeljs.io/), [Jest](https://jestjs.io/), [Reason](https://reasonml.github.io/) and [Prettier](https://prettier.io/). @@ -107,7 +108,7 @@ If you've read the post up until to this point, you should be able to notice tha The exact list of breaking changes is not totally known yet as development is not 100% finalized. However, one thing that I will highlight is that we will deprecate a lot of options in `siteConfig.js` and we plan to keep it as lean as possible. For example, the `cleanUrl` siteConfig will be deprecated as all the URL for Docusaurus 2 sites will be without the `.html` suffix. -Our goal is that most sites should be able to upgrade to Docusaurus 2 without a lot of pain. We will also include a migration guide when we release Docusaurus 2. When the times come, feel free to ping us on [Discord](https://discord.gg/docusaurus) or [Twitter](https://twitter.com/docusaurus) for questions and help. +Our goal is that most sites should be able to upgrade to Docusaurus 2 without a lot of pain. We will also include a migration guide when we release Docusaurus 2. When the times come, feel free to ping us on [Discord](https://discord.gg/docusaurus) or [Twitter](https://twitter.com/docusaurus) for questions and help. ### When is the release of Docusaurus 2? diff --git a/website-1.x/blog/2018-12-14-Happy-First-Birthday-Slash.md b/website-1.x/blog/2018-12-14-Happy-First-Birthday-Slash.md index 06366432b7..97b54fa7a1 100644 --- a/website-1.x/blog/2018-12-14-Happy-First-Birthday-Slash.md +++ b/website-1.x/blog/2018-12-14-Happy-First-Birthday-Slash.md @@ -5,6 +5,7 @@ authorTitle: Co-creator of Docusaurus authorURL: https://github.com/JoelMarcey authorFBID: 611217057 authorTwitter: JoelMarcey +tags: [birth] --- ![First Birthday Slash](/img/docusaurus-slash-first-birthday.svg)