feat(v2): blog tags (#1453)

* feat(v2): blog tags

* feat(v2): blog tags
This commit is contained in:
Yangshun Tay 2019-05-13 10:14:44 -07:00 committed by GitHub
parent ffdd3e60fc
commit fd270bdceb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 218 additions and 3 deletions

View file

@ -26,6 +26,8 @@ const DEFAULT_OPTIONS = {
postsPerPage: 10, // How many posts per page. postsPerPage: 10, // How many posts per page.
blogListComponent: '@theme/BlogListPage', blogListComponent: '@theme/BlogListPage',
blogPostComponent: '@theme/BlogPostPage', blogPostComponent: '@theme/BlogPostPage',
blogTagsListComponent: '@theme/BlogTagsListPage',
blogTagsPostsComponent: '@theme/BlogTagsPostsPage',
}; };
class DocusaurusPluginContentBlog { class DocusaurusPluginContentBlog {
@ -87,6 +89,7 @@ class DocusaurusPluginContentBlog {
source, source,
description: frontMatter.description || excerpt, description: frontMatter.description || excerpt,
date, date,
tags: frontMatter.tags,
title: frontMatter.title || blogFileName, 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 { return {
blogPosts, blogPosts,
blogListPaginated, blogListPaginated,
blogTags,
}; };
} }
async contentLoaded({content: blogContents, actions}) { async contentLoaded({content: blogContents, actions}) {
const {blogListComponent, blogPostComponent} = this.options; const {
blogListComponent,
blogPostComponent,
blogTagsListComponent,
blogTagsPostsComponent,
} = this.options;
const {addRoute, createData} = actions; const {addRoute, createData} = actions;
const {blogPosts, blogListPaginated} = blogContents; const {blogPosts, blogListPaginated, blogTags} = blogContents;
const blogItemsToModules = {}; const blogItemsToModules = {};
// Create routes for blog entries. // 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() { getThemePath() {

View file

@ -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 (
<div key={letter}>
<h3>{letter}</h3>
{tagsForLetter.map(tag => (
<Link
className="padding-right--md"
href={tags[tag].permalink}
key="tag">
{tag} ({tags[tag].count})
</Link>
))}
<hr />
</div>
);
})
.filter(item => item != null);
return (
<Layout title="Blog Tags" description="Blog Tags">
<div className="container margin-vert--xl">
<div className="row">
<div className="col col--8 col--offset-2">
<h1>Tags</h1>
<div className="margin-vert--lg">{tagsSection}</div>
</div>
</div>
</div>
</Layout>
);
}
export default BlogTagsListPage;

View file

@ -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 (
<Layout title={`Blog | Tagged ${tag}`} description={`Blog | Tagged ${tag}`}>
<div className="container margin-vert--xl">
<div className="row">
<div className="col col--8 col--offset-2">
<h1>
{items.length} post(s) tagged with &quot;{tag}&quot;
</h1>
<div className="margin-vert--lg">
{items.map(
({content: BlogPostContent, metadata: blogPostMetadata}) => (
<div key={blogPostMetadata.permalink}>
<BlogPostItem
frontMatter={BlogPostContent.frontMatter}
metadata={blogPostMetadata}
truncated>
<BlogPostContent />
</BlogPostItem>
</div>
),
)}
</div>
</div>
</div>
</div>
</Layout>
);
}
export default BlogTagsPostPage;

View file

@ -4,6 +4,7 @@ author: Joel Marcey
authorURL: http://twitter.com/JoelMarcey authorURL: http://twitter.com/JoelMarcey
authorFBID: 611217057 authorFBID: 611217057
authorTwitter: JoelMarcey authorTwitter: JoelMarcey
tags: [birth]
--- ---
![Introducing Slash](/img/slash-introducing.svg) ![Introducing Slash](/img/slash-introducing.svg)

View file

@ -4,6 +4,7 @@ author: Christine Abernathy
authorURL: http://twitter.com/abernathyca authorURL: http://twitter.com/abernathyca
authorFBID: 1424840234 authorFBID: 1424840234
authorTwitter: abernathyca 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.”* > *“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.”*

View file

@ -5,6 +5,7 @@ authorTitle: Maintainer of Docusaurus
authorURL: https://github.com/endiliey authorURL: https://github.com/endiliey
authorImageURL: https://avatars1.githubusercontent.com/u/17883920?s=460&v=4 authorImageURL: https://avatars1.githubusercontent.com/u/17883920?s=460&v=4
authorTwitter: endiliey 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/). 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/).

View file

@ -5,6 +5,7 @@ authorTitle: Co-creator of Docusaurus
authorURL: https://github.com/JoelMarcey authorURL: https://github.com/JoelMarcey
authorFBID: 611217057 authorFBID: 611217057
authorTwitter: JoelMarcey authorTwitter: JoelMarcey
tags: [birth]
--- ---
![First Birthday Slash](/img/docusaurus-slash-first-birthday.svg) ![First Birthday Slash](/img/docusaurus-slash-first-birthday.svg)