mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-04 04:37:28 +02:00
feat(v2): blog tags (#1453)
* feat(v2): blog tags * feat(v2): blog tags
This commit is contained in:
parent
ffdd3e60fc
commit
fd270bdceb
7 changed files with 218 additions and 3 deletions
|
@ -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() {
|
||||
|
|
|
@ -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;
|
|
@ -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 "{tag}"
|
||||
</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;
|
|
@ -4,6 +4,7 @@ author: Joel Marcey
|
|||
authorURL: http://twitter.com/JoelMarcey
|
||||
authorFBID: 611217057
|
||||
authorTwitter: JoelMarcey
|
||||
tags: [birth]
|
||||
---
|
||||
|
||||

|
||||
|
|
|
@ -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.”*
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -5,6 +5,7 @@ authorTitle: Co-creator of Docusaurus
|
|||
authorURL: https://github.com/JoelMarcey
|
||||
authorFBID: 611217057
|
||||
authorTwitter: JoelMarcey
|
||||
tags: [birth]
|
||||
---
|
||||
|
||||

|
||||
|
|
Loading…
Add table
Reference in a new issue