mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-18 11:36:53 +02:00
feat(v2): blog sidebar (#3593)
* blog sidebar POC * polish blog post sidebar * add doc for blogSidebarCount * Update packages/docusaurus-theme-classic/src/theme/BlogSidebar/styles.module.css Co-authored-by: Alexey Pyltsyn <lex61rus@gmail.com> Co-authored-by: Alexey Pyltsyn <lex61rus@gmail.com>
This commit is contained in:
parent
da6268911c
commit
e4c1626106
14 changed files with 226 additions and 14 deletions
|
@ -81,3 +81,42 @@ test('should convert all feed type to array with other feed type', () => {
|
|||
feedOptions: {type: ['rss', 'atom']},
|
||||
});
|
||||
});
|
||||
|
||||
describe('blog sidebar', () => {
|
||||
test('should accept 0 sidebar count', () => {
|
||||
const userOptions = {blogSidebarCount: 0};
|
||||
const {value, error} = PluginOptionSchema.validate(userOptions);
|
||||
expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions});
|
||||
expect(error).toBe(undefined);
|
||||
});
|
||||
|
||||
test('should accept "ALL" sidebar count', () => {
|
||||
const userOptions = {blogSidebarCount: 'ALL'};
|
||||
const {value, error} = PluginOptionSchema.validate(userOptions);
|
||||
expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions});
|
||||
expect(error).toBe(undefined);
|
||||
});
|
||||
|
||||
test('should reject "abcdef" sidebar count', () => {
|
||||
const userOptions = {blogSidebarCount: 'abcdef'};
|
||||
const {error} = PluginOptionSchema.validate(userOptions);
|
||||
expect(error).toMatchInlineSnapshot(
|
||||
`[ValidationError: "blogSidebarCount" must be one of [ALL, number]]`,
|
||||
);
|
||||
});
|
||||
|
||||
test('should accept "all posts" sidebar title', () => {
|
||||
const userOptions = {blogSidebarTitle: 'all posts'};
|
||||
const {value, error} = PluginOptionSchema.validate(userOptions);
|
||||
expect(value).toEqual({...DEFAULT_OPTIONS, ...userOptions});
|
||||
expect(error).toBe(undefined);
|
||||
});
|
||||
|
||||
test('should reject 42 sidebar title', () => {
|
||||
const userOptions = {blogSidebarTitle: 42};
|
||||
const {error} = PluginOptionSchema.validate(userOptions);
|
||||
expect(error).toMatchInlineSnapshot(
|
||||
`[ValidationError: "blogSidebarTitle" must be a string]`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import kebabCase from 'lodash.kebabcase';
|
||||
import path from 'path';
|
||||
import admonitions from 'remark-admonitions';
|
||||
import {normalizeUrl, docuHash, aliasedSitePath} from '@docusaurus/utils';
|
||||
|
@ -15,6 +14,7 @@ import {
|
|||
DEFAULT_PLUGIN_ID,
|
||||
} from '@docusaurus/core/lib/constants';
|
||||
import {ValidationError} from '@hapi/joi';
|
||||
import {take, kebabCase} from 'lodash';
|
||||
|
||||
import {
|
||||
PluginOptions,
|
||||
|
@ -50,12 +50,13 @@ export default function pluginContentBlog(
|
|||
|
||||
const {siteDir, generatedFilesDir} = context;
|
||||
const contentPath = path.resolve(siteDir, options.path);
|
||||
const pluginId = options.id ?? DEFAULT_PLUGIN_ID;
|
||||
|
||||
const pluginDataDirRoot = path.join(
|
||||
generatedFilesDir,
|
||||
'docusaurus-plugin-content-blog',
|
||||
);
|
||||
const dataDir = path.join(pluginDataDirRoot, options.id ?? DEFAULT_PLUGIN_ID);
|
||||
const dataDir = path.join(pluginDataDirRoot, pluginId);
|
||||
const aliasedSource = (source: string) =>
|
||||
`~blog/${path.relative(pluginDataDirRoot, source)}`;
|
||||
|
||||
|
@ -217,6 +218,29 @@ export default function pluginContentBlog(
|
|||
|
||||
const blogItemsToMetadata: BlogItemsToMetadata = {};
|
||||
|
||||
const sidebarBlogPosts =
|
||||
options.blogSidebarCount === 'ALL'
|
||||
? blogPosts
|
||||
: take(blogPosts, options.blogSidebarCount);
|
||||
|
||||
// This prop is useful to provide the blog list sidebar
|
||||
const sidebarProp = await createData(
|
||||
// Note that this created data path must be in sync with
|
||||
// metadataPath provided to mdx-loader.
|
||||
`blog-post-list-prop-${pluginId}.json`,
|
||||
JSON.stringify(
|
||||
{
|
||||
title: options.blogSidebarTitle,
|
||||
items: sidebarBlogPosts.map((blogPost) => ({
|
||||
title: blogPost.metadata.title,
|
||||
permalink: blogPost.metadata.permalink,
|
||||
})),
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
|
||||
// Create routes for blog entries.
|
||||
await Promise.all(
|
||||
loadedBlogPosts.map(async (blogPost) => {
|
||||
|
@ -233,6 +257,7 @@ export default function pluginContentBlog(
|
|||
component: blogPostComponent,
|
||||
exact: true,
|
||||
modules: {
|
||||
sidebar: sidebarProp,
|
||||
content: metadata.source,
|
||||
},
|
||||
});
|
||||
|
@ -256,6 +281,7 @@ export default function pluginContentBlog(
|
|||
component: blogListComponent,
|
||||
exact: true,
|
||||
modules: {
|
||||
sidebar: sidebarProp,
|
||||
items: items.map((postID) => {
|
||||
// To tell routes.js this is an import and not a nested object to recurse.
|
||||
return {
|
||||
|
@ -303,6 +329,7 @@ export default function pluginContentBlog(
|
|||
component: blogTagsPostsComponent,
|
||||
exact: true,
|
||||
modules: {
|
||||
sidebar: sidebarProp,
|
||||
items: items.map((postID) => {
|
||||
const metadata = blogItemsToMetadata[postID];
|
||||
return {
|
||||
|
@ -333,6 +360,7 @@ export default function pluginContentBlog(
|
|||
component: blogTagsListComponent,
|
||||
exact: true,
|
||||
modules: {
|
||||
sidebar: sidebarProp,
|
||||
tags: aliasedSource(tagsListPath),
|
||||
},
|
||||
});
|
||||
|
|
|
@ -28,6 +28,8 @@ export const DEFAULT_OPTIONS = {
|
|||
blogListComponent: '@theme/BlogListPage',
|
||||
blogDescription: 'Blog',
|
||||
blogTitle: 'Blog',
|
||||
blogSidebarCount: 5,
|
||||
blogSidebarTitle: 'Recent posts',
|
||||
postsPerPage: 10,
|
||||
include: ['*.md', '*.mdx'],
|
||||
routeBasePath: 'blog',
|
||||
|
@ -57,6 +59,10 @@ export const PluginOptionSchema = Joi.object({
|
|||
blogDescription: Joi.string()
|
||||
.allow('')
|
||||
.default(DEFAULT_OPTIONS.blogDescription),
|
||||
blogSidebarCount: Joi.alternatives()
|
||||
.try(Joi.equal('ALL').required(), Joi.number().required())
|
||||
.default(DEFAULT_OPTIONS.blogSidebarCount),
|
||||
blogSidebarTitle: Joi.string().default(DEFAULT_OPTIONS.blogSidebarTitle),
|
||||
showReadingTime: Joi.bool().default(DEFAULT_OPTIONS.showReadingTime),
|
||||
remarkPlugins: RemarkPluginsSchema.default(DEFAULT_OPTIONS.remarkPlugins),
|
||||
rehypePlugins: RehypePluginsSchema.default(DEFAULT_OPTIONS.rehypePlugins),
|
||||
|
|
|
@ -31,6 +31,8 @@ export interface PluginOptions {
|
|||
blogTagsPostsComponent: string;
|
||||
blogTitle: string;
|
||||
blogDescription: string;
|
||||
blogSidebarCount: number | 'ALL';
|
||||
blogSidebarTitle: string;
|
||||
remarkPlugins: ([Function, object] | Function)[];
|
||||
beforeDefaultRehypePlugins: ([Function, object] | Function)[];
|
||||
beforeDefaultRemarkPlugins: ([Function, object] | Function)[];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue