123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- const blogPluginExports = require("@docusaurus/plugin-content-blog");
- const utils = require("@docusaurus/utils");
- const path = require("path");
- const defaultBlogPlugin = blogPluginExports.default;
- const pluginDataDirRoot = path.join(
- ".docusaurus",
- "docusaurus-plugin-content-blog",
- );
- const aliasedSource = (source) =>
- `~blog/${utils.posixPath(path.relative(pluginDataDirRoot, source))}`;
- function paginateBlogPosts({
- blogPosts,
- basePageUrl,
- blogTitle,
- blogDescription,
- postsPerPageOption,
- }) {
- const totalCount = blogPosts.length;
- const postsPerPage =
- postsPerPageOption === "ALL" ? totalCount : postsPerPageOption;
- const numberOfPages = Math.ceil(totalCount / postsPerPage);
- const pages = [];
- function permalink(page) {
- return page > 0
- ? utils.normalizeUrl([basePageUrl, `page/${page + 1}`])
- : basePageUrl;
- }
- for (let page = 0; page < numberOfPages; page += 1) {
- pages.push({
- items: blogPosts
- .slice(page * postsPerPage, (page + 1) * postsPerPage)
- .map((item) => item.id),
- metadata: {
- permalink: permalink(page),
- page: page + 1,
- postsPerPage,
- totalPages: numberOfPages,
- totalCount,
- previousPage: page !== 0 ? permalink(page - 1) : undefined,
- nextPage:
- page < numberOfPages - 1 ? permalink(page + 1) : undefined,
- blogDescription,
- blogTitle,
- },
- });
- }
- return pages;
- }
- function getMultipleRandomElement(arr, num) {
- const shuffled = [...arr].sort(() => 0.5 - Math.random());
- return shuffled.slice(0, num);
- }
- function getReletadPosts(allBlogPosts, metadata) {
- const relatedPosts = allBlogPosts.filter(
- (post) =>
- post.metadata.frontMatter.tags?.some((tag) =>
- metadata.frontMatter.tags?.includes(tag),
- ) && post.metadata.title !== metadata.title,
- );
- const randomThreeRelatedPosts = getMultipleRandomElement(relatedPosts, 3);
- const filteredPostInfos = randomThreeRelatedPosts.map((post) => {
- return {
- title: post.metadata.title,
- description: post.metadata.description,
- permalink: post.metadata.permalink,
- formattedDate: post.metadata.formattedDate,
- authors: post.metadata.authors,
- readingTime: post.metadata.readingTime,
- date: post.metadata.date,
- };
- });
- return filteredPostInfos;
- }
- function getAuthorPosts(allBlogPosts, metadata) {
- const authorPosts = allBlogPosts.filter(
- (post) =>
- post.metadata.frontMatter.authors ===
- metadata.frontMatter.authors &&
- post.metadata.title !== metadata.title,
- );
- const randomThreeAuthorPosts = getMultipleRandomElement(authorPosts, 3);
- const filteredPostInfos = randomThreeAuthorPosts.map((post) => {
- return {
- title: post.metadata.title,
- description: post.metadata.description,
- permalink: post.metadata.permalink,
- formattedDate: post.metadata.formattedDate,
- authors: post.metadata.authors,
- readingTime: post.metadata.readingTime,
- date: post.metadata.date,
- };
- });
- return filteredPostInfos;
- }
- async function blogPluginExtended(...pluginArgs) {
- const blogPluginInstance = await defaultBlogPlugin(...pluginArgs);
- const { blogTitle, blogDescription, postsPerPage } = pluginArgs[1];
- return {
- // Add all properties of the default blog plugin so existing functionality is preserved
- ...blogPluginInstance,
- /**
- * Override the default `contentLoaded` hook to access blog posts data
- */
- contentLoaded: async function (data) {
- const { content: blogContents, actions } = data;
- const { addRoute, createData } = actions;
- const {
- blogPosts: allBlogPosts,
- blogTags,
- blogTagsListPath,
- } = blogContents;
- const blogItemsToMetadata = {};
- function blogPostItemsModule(items) {
- return items.map((postId) => {
- const blogPostMetadata = blogItemsToMetadata[postId];
- return {
- content: {
- __import: true,
- path: blogPostMetadata.source,
- query: {
- truncated: true,
- },
- },
- };
- });
- }
- const featuredBlogPosts = allBlogPosts.filter(
- (post) => post.metadata.frontMatter.is_featured === true,
- );
- const blogPosts = allBlogPosts.filter(
- (post) => post.metadata.frontMatter.is_featured !== true,
- );
- const blogListPaginated = paginateBlogPosts({
- blogPosts,
- basePageUrl: "/blog",
- blogTitle,
- blogDescription,
- postsPerPageOption: postsPerPage,
- });
- // Create routes for blog entries.
- await Promise.all(
- allBlogPosts.map(async (blogPost) => {
- const { id, metadata } = blogPost;
- const relatedPosts = getReletadPosts(
- allBlogPosts,
- metadata,
- );
- const authorPosts = getAuthorPosts(allBlogPosts, metadata);
- await createData(
- // Note that this created data path must be in sync with
- // metadataPath provided to mdx-loader.
- `${utils.docuHash(metadata.source)}.json`,
- JSON.stringify(
- { ...metadata, relatedPosts, authorPosts },
- null,
- 2,
- ),
- );
- addRoute({
- path: metadata.permalink,
- component: "@theme/BlogPostPage",
- exact: true,
- modules: {
- content: metadata.source,
- },
- });
- blogItemsToMetadata[id] = metadata;
- }),
- );
- // Create routes for blog's paginated list entries.
- await Promise.all(
- blogListPaginated.map(async (listPage) => {
- const { metadata, items } = listPage;
- const { permalink } = metadata;
- const pageMetadataPath = await createData(
- `${utils.docuHash(permalink)}.json`,
- JSON.stringify(metadata, null, 2),
- );
- const tagsProp = Object.values(blogTags).map((tag) => ({
- label: tag.label,
- permalink: tag.permalink,
- count: tag.items.length,
- }));
- const tagsPropPath = await createData(
- `${utils.docuHash(`${blogTagsListPath}-tags`)}.json`,
- JSON.stringify(tagsProp, null, 2),
- );
- addRoute({
- path: permalink,
- component: "@theme/BlogListPage",
- exact: true,
- modules: {
- items: blogPostItemsModule(
- permalink === "/blog"
- ? [
- ...items,
- ...featuredBlogPosts.map(
- (post) => post.id,
- ),
- ]
- : items,
- ),
- metadata: aliasedSource(pageMetadataPath),
- tags: aliasedSource(tagsPropPath),
- },
- });
- }),
- );
- const authorsArray = allBlogPosts
- .map((post) => post.metadata.frontMatter.authors)
- .filter((authorName) => authorName !== undefined);
- const uniqueAuthors = [...new Set(authorsArray)];
- uniqueAuthors.map(async (author) => {
- const authorPosts = allBlogPosts.filter(
- (post) => post.metadata.frontMatter.authors === author,
- );
- const authorListPaginated = paginateBlogPosts({
- blogPosts: authorPosts,
- basePageUrl: "/blog/author/" + author,
- blogTitle,
- blogDescription,
- postsPerPageOption: "ALL",
- });
- authorListPaginated.map((authorListPage) => {
- const { metadata, items } = authorListPage;
- const { permalink } = metadata;
- addRoute({
- path: permalink,
- component: "@site/src/components/blog/author-page",
- exact: true,
- modules: {
- items: blogPostItemsModule(items),
- },
- });
- });
- });
- // Tags. This is the last part so we early-return if there are no tags.
- if (Object.keys(blogTags).length === 0) {
- return;
- }
- async function createTagsListPage() {
- const tagsProp = Object.values(blogTags).map((tag) => ({
- label: tag.label,
- permalink: tag.permalink,
- count: tag.items.length,
- }));
- const tagsPropPath = await createData(
- `${utils.docuHash(`${blogTagsListPath}-tags`)}.json`,
- JSON.stringify(tagsProp, null, 2),
- );
- addRoute({
- path: blogTagsListPath,
- component: "@theme/BlogTagsListPage",
- exact: true,
- modules: {
- tags: aliasedSource(tagsPropPath),
- },
- });
- }
- async function createTagPostsListPage(tag) {
- await Promise.all(
- tag.pages.map(async (blogPaginated) => {
- const { metadata, items } = blogPaginated;
- const tagProp = {
- label: tag.label,
- permalink: tag.permalink,
- allTagsPath: blogTagsListPath,
- count: tag.items.length,
- };
- const tagPropPath = await createData(
- `${utils.docuHash(metadata.permalink)}.json`,
- JSON.stringify(tagProp, null, 2),
- );
- const listMetadataPath = await createData(
- `${utils.docuHash(metadata.permalink)}-list.json`,
- JSON.stringify(metadata, null, 2),
- );
- const tagsProp = Object.values(blogTags).map((tag) => ({
- label: tag.label,
- permalink: tag.permalink,
- count: tag.items.length,
- }));
- const tagsPropPath = await createData(
- `${utils.docuHash(
- `${blogTagsListPath}-tags`,
- )}.json`,
- JSON.stringify(tagsProp, null, 2),
- );
- addRoute({
- path: metadata.permalink,
- component: "@theme/BlogTagsPostsPage",
- exact: true,
- modules: {
- items: blogPostItemsModule(items),
- tag: aliasedSource(tagPropPath),
- tags: aliasedSource(tagsPropPath),
- listMetadata: aliasedSource(listMetadataPath),
- },
- });
- }),
- );
- }
- await createTagsListPage();
- await Promise.all(
- Object.values(blogTags).map(createTagPostsListPage),
- );
- },
- };
- }
- module.exports = {
- ...blogPluginExports,
- default: blogPluginExtended,
- };
|