mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-02 03:37:48 +02:00
feat(blog): add blog pageBasePath plugin option (#9838)
Co-authored-by: sebastien <lorber.sebastien@gmail.com>
This commit is contained in:
parent
cc7f43580c
commit
70ba9d2d01
8 changed files with 113 additions and 21 deletions
|
@ -23,7 +23,32 @@ title: This post links to another one!
|
||||||
[Linked post](/blog/2018/12/14/Happy-First-Birthday-Slash)"
|
[Linked post](/blog/2018/12/14/Happy-First-Birthday-Slash)"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`paginateBlogPosts generates right pages 1`] = `
|
exports[`paginateBlogPosts generates a single page 1`] = `
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
"post1",
|
||||||
|
"post2",
|
||||||
|
"post3",
|
||||||
|
"post4",
|
||||||
|
"post5",
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"blogDescription": "Blog Description",
|
||||||
|
"blogTitle": "Blog Title",
|
||||||
|
"nextPage": undefined,
|
||||||
|
"page": 1,
|
||||||
|
"permalink": "/",
|
||||||
|
"postsPerPage": 10,
|
||||||
|
"previousPage": undefined,
|
||||||
|
"totalCount": 5,
|
||||||
|
"totalPages": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`paginateBlogPosts generates pages 1`] = `
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"items": [
|
"items": [
|
||||||
|
@ -78,7 +103,7 @@ exports[`paginateBlogPosts generates right pages 1`] = `
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`paginateBlogPosts generates right pages 2`] = `
|
exports[`paginateBlogPosts generates pages at blog root 1`] = `
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"items": [
|
"items": [
|
||||||
|
@ -133,26 +158,56 @@ exports[`paginateBlogPosts generates right pages 2`] = `
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`paginateBlogPosts generates right pages 3`] = `
|
exports[`paginateBlogPosts generates pages with custom pageBasePath 1`] = `
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"items": [
|
"items": [
|
||||||
"post1",
|
"post1",
|
||||||
"post2",
|
"post2",
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"blogDescription": "Blog Description",
|
||||||
|
"blogTitle": "Blog Title",
|
||||||
|
"nextPage": "/blog/customPageBasePath/2",
|
||||||
|
"page": 1,
|
||||||
|
"permalink": "/blog",
|
||||||
|
"postsPerPage": 2,
|
||||||
|
"previousPage": undefined,
|
||||||
|
"totalCount": 5,
|
||||||
|
"totalPages": 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
"post3",
|
"post3",
|
||||||
"post4",
|
"post4",
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"blogDescription": "Blog Description",
|
||||||
|
"blogTitle": "Blog Title",
|
||||||
|
"nextPage": "/blog/customPageBasePath/3",
|
||||||
|
"page": 2,
|
||||||
|
"permalink": "/blog/customPageBasePath/2",
|
||||||
|
"postsPerPage": 2,
|
||||||
|
"previousPage": "/blog",
|
||||||
|
"totalCount": 5,
|
||||||
|
"totalPages": 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
"post5",
|
"post5",
|
||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"blogDescription": "Blog Description",
|
"blogDescription": "Blog Description",
|
||||||
"blogTitle": "Blog Title",
|
"blogTitle": "Blog Title",
|
||||||
"nextPage": undefined,
|
"nextPage": undefined,
|
||||||
"page": 1,
|
"page": 3,
|
||||||
"permalink": "/",
|
"permalink": "/blog/customPageBasePath/3",
|
||||||
"postsPerPage": 10,
|
"postsPerPage": 2,
|
||||||
"previousPage": undefined,
|
"previousPage": "/blog/customPageBasePath/2",
|
||||||
"totalCount": 5,
|
"totalCount": 5,
|
||||||
"totalPages": 1,
|
"totalPages": 3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -38,7 +38,6 @@ describe('truncate', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('paginateBlogPosts', () => {
|
describe('paginateBlogPosts', () => {
|
||||||
it('generates right pages', () => {
|
|
||||||
const blogPosts = [
|
const blogPosts = [
|
||||||
{id: 'post1', metadata: {}, content: 'Foo 1'},
|
{id: 'post1', metadata: {}, content: 'Foo 1'},
|
||||||
{id: 'post2', metadata: {}, content: 'Foo 2'},
|
{id: 'post2', metadata: {}, content: 'Foo 2'},
|
||||||
|
@ -46,6 +45,8 @@ describe('paginateBlogPosts', () => {
|
||||||
{id: 'post4', metadata: {}, content: 'Foo 4'},
|
{id: 'post4', metadata: {}, content: 'Foo 4'},
|
||||||
{id: 'post5', metadata: {}, content: 'Foo 5'},
|
{id: 'post5', metadata: {}, content: 'Foo 5'},
|
||||||
] as BlogPost[];
|
] as BlogPost[];
|
||||||
|
|
||||||
|
it('generates pages', () => {
|
||||||
expect(
|
expect(
|
||||||
paginateBlogPosts({
|
paginateBlogPosts({
|
||||||
blogPosts,
|
blogPosts,
|
||||||
|
@ -53,8 +54,12 @@ describe('paginateBlogPosts', () => {
|
||||||
blogTitle: 'Blog Title',
|
blogTitle: 'Blog Title',
|
||||||
blogDescription: 'Blog Description',
|
blogDescription: 'Blog Description',
|
||||||
postsPerPageOption: 2,
|
postsPerPageOption: 2,
|
||||||
|
pageBasePath: 'page',
|
||||||
}),
|
}),
|
||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('generates pages at blog root', () => {
|
||||||
expect(
|
expect(
|
||||||
paginateBlogPosts({
|
paginateBlogPosts({
|
||||||
blogPosts,
|
blogPosts,
|
||||||
|
@ -62,8 +67,12 @@ describe('paginateBlogPosts', () => {
|
||||||
blogTitle: 'Blog Title',
|
blogTitle: 'Blog Title',
|
||||||
blogDescription: 'Blog Description',
|
blogDescription: 'Blog Description',
|
||||||
postsPerPageOption: 2,
|
postsPerPageOption: 2,
|
||||||
|
pageBasePath: 'page',
|
||||||
}),
|
}),
|
||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('generates a single page', () => {
|
||||||
expect(
|
expect(
|
||||||
paginateBlogPosts({
|
paginateBlogPosts({
|
||||||
blogPosts,
|
blogPosts,
|
||||||
|
@ -71,6 +80,20 @@ describe('paginateBlogPosts', () => {
|
||||||
blogTitle: 'Blog Title',
|
blogTitle: 'Blog Title',
|
||||||
blogDescription: 'Blog Description',
|
blogDescription: 'Blog Description',
|
||||||
postsPerPageOption: 10,
|
postsPerPageOption: 10,
|
||||||
|
pageBasePath: 'page',
|
||||||
|
}),
|
||||||
|
).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('generates pages with custom pageBasePath', () => {
|
||||||
|
expect(
|
||||||
|
paginateBlogPosts({
|
||||||
|
blogPosts,
|
||||||
|
basePageUrl: '/blog',
|
||||||
|
blogTitle: 'Blog Title',
|
||||||
|
blogDescription: 'Blog Description',
|
||||||
|
postsPerPageOption: 2,
|
||||||
|
pageBasePath: 'customPageBasePath',
|
||||||
}),
|
}),
|
||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
|
@ -57,12 +57,14 @@ export function paginateBlogPosts({
|
||||||
blogTitle,
|
blogTitle,
|
||||||
blogDescription,
|
blogDescription,
|
||||||
postsPerPageOption,
|
postsPerPageOption,
|
||||||
|
pageBasePath,
|
||||||
}: {
|
}: {
|
||||||
blogPosts: BlogPost[];
|
blogPosts: BlogPost[];
|
||||||
basePageUrl: string;
|
basePageUrl: string;
|
||||||
blogTitle: string;
|
blogTitle: string;
|
||||||
blogDescription: string;
|
blogDescription: string;
|
||||||
postsPerPageOption: number | 'ALL';
|
postsPerPageOption: number | 'ALL';
|
||||||
|
pageBasePath: string;
|
||||||
}): BlogPaginated[] {
|
}): BlogPaginated[] {
|
||||||
const totalCount = blogPosts.length;
|
const totalCount = blogPosts.length;
|
||||||
const postsPerPage =
|
const postsPerPage =
|
||||||
|
@ -73,7 +75,7 @@ export function paginateBlogPosts({
|
||||||
|
|
||||||
function permalink(page: number) {
|
function permalink(page: number) {
|
||||||
return page > 0
|
return page > 0
|
||||||
? normalizeUrl([basePageUrl, `page/${page + 1}`])
|
? normalizeUrl([basePageUrl, pageBasePath, `${page + 1}`])
|
||||||
: basePageUrl;
|
: basePageUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +113,7 @@ export function getBlogTags({
|
||||||
blogTitle: string;
|
blogTitle: string;
|
||||||
blogDescription: string;
|
blogDescription: string;
|
||||||
postsPerPageOption: number | 'ALL';
|
postsPerPageOption: number | 'ALL';
|
||||||
|
pageBasePath: string;
|
||||||
}): BlogTags {
|
}): BlogTags {
|
||||||
const groups = groupTaggedItems(
|
const groups = groupTaggedItems(
|
||||||
blogPosts,
|
blogPosts,
|
||||||
|
|
|
@ -107,6 +107,7 @@ export default async function pluginContentBlog(
|
||||||
blogDescription,
|
blogDescription,
|
||||||
blogTitle,
|
blogTitle,
|
||||||
blogSidebarTitle,
|
blogSidebarTitle,
|
||||||
|
pageBasePath,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
|
const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
|
||||||
|
@ -121,11 +122,10 @@ export default async function pluginContentBlog(
|
||||||
blogListPaginated: [],
|
blogListPaginated: [],
|
||||||
blogTags: {},
|
blogTags: {},
|
||||||
blogTagsListPath,
|
blogTagsListPath,
|
||||||
blogTagsPaginated: [],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Colocate next and prev metadata.
|
// Collocate next and prev metadata.
|
||||||
listedBlogPosts.forEach((blogPost, index) => {
|
listedBlogPosts.forEach((blogPost, index) => {
|
||||||
const prevItem = index > 0 ? listedBlogPosts[index - 1] : null;
|
const prevItem = index > 0 ? listedBlogPosts[index - 1] : null;
|
||||||
if (prevItem) {
|
if (prevItem) {
|
||||||
|
@ -153,6 +153,7 @@ export default async function pluginContentBlog(
|
||||||
blogDescription,
|
blogDescription,
|
||||||
postsPerPageOption,
|
postsPerPageOption,
|
||||||
basePageUrl: baseBlogUrl,
|
basePageUrl: baseBlogUrl,
|
||||||
|
pageBasePath,
|
||||||
});
|
});
|
||||||
|
|
||||||
const blogTags: BlogTags = getBlogTags({
|
const blogTags: BlogTags = getBlogTags({
|
||||||
|
@ -160,6 +161,7 @@ export default async function pluginContentBlog(
|
||||||
postsPerPageOption,
|
postsPerPageOption,
|
||||||
blogDescription,
|
blogDescription,
|
||||||
blogTitle,
|
blogTitle,
|
||||||
|
pageBasePath,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -45,6 +45,7 @@ export const DEFAULT_OPTIONS: PluginOptions = {
|
||||||
routeBasePath: 'blog',
|
routeBasePath: 'blog',
|
||||||
tagsBasePath: 'tags',
|
tagsBasePath: 'tags',
|
||||||
archiveBasePath: 'archive',
|
archiveBasePath: 'archive',
|
||||||
|
pageBasePath: 'page',
|
||||||
path: 'blog',
|
path: 'blog',
|
||||||
editLocalizedFiles: false,
|
editLocalizedFiles: false,
|
||||||
authorsMapPath: 'authors.yml',
|
authorsMapPath: 'authors.yml',
|
||||||
|
@ -59,6 +60,7 @@ const PluginOptionSchema = Joi.object<PluginOptions>({
|
||||||
.allow(null),
|
.allow(null),
|
||||||
routeBasePath: RouteBasePathSchema.default(DEFAULT_OPTIONS.routeBasePath),
|
routeBasePath: RouteBasePathSchema.default(DEFAULT_OPTIONS.routeBasePath),
|
||||||
tagsBasePath: Joi.string().default(DEFAULT_OPTIONS.tagsBasePath),
|
tagsBasePath: Joi.string().default(DEFAULT_OPTIONS.tagsBasePath),
|
||||||
|
pageBasePath: Joi.string().default(DEFAULT_OPTIONS.pageBasePath),
|
||||||
include: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.include),
|
include: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.include),
|
||||||
exclude: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.exclude),
|
exclude: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.exclude),
|
||||||
postsPerPage: Joi.alternatives()
|
postsPerPage: Joi.alternatives()
|
||||||
|
|
|
@ -351,9 +351,14 @@ yarn workspace v1.22.19image` is a collocated image path, this entry will be the
|
||||||
routeBasePath: string;
|
routeBasePath: string;
|
||||||
/**
|
/**
|
||||||
* URL route for the tags section of your blog. Will be appended to
|
* URL route for the tags section of your blog. Will be appended to
|
||||||
* `routeBasePath`. **DO NOT** include a trailing slash.
|
* `routeBasePath`.
|
||||||
*/
|
*/
|
||||||
tagsBasePath: string;
|
tagsBasePath: string;
|
||||||
|
/**
|
||||||
|
* URL route for the pages section of your blog. Will be appended to
|
||||||
|
* `routeBasePath`.
|
||||||
|
*/
|
||||||
|
pageBasePath: string;
|
||||||
/**
|
/**
|
||||||
* URL route for the archive section of your blog. Will be appended to
|
* URL route for the archive section of your blog. Will be appended to
|
||||||
* `routeBasePath`. **DO NOT** include a trailing slash. Use `null` to
|
* `routeBasePath`. **DO NOT** include a trailing slash. Use `null` to
|
||||||
|
|
|
@ -53,6 +53,7 @@ The component used for Markdown pages is `@theme/MDXPage`. React pages are direc
|
||||||
The blog creates the following routes:
|
The blog creates the following routes:
|
||||||
|
|
||||||
- **Posts list pages**: `/`, `/page/2`, `/page/3`...
|
- **Posts list pages**: `/`, `/page/2`, `/page/3`...
|
||||||
|
- The route is customizable through the `pageBasePath` option.
|
||||||
- The component is `@theme/BlogListPage`.
|
- The component is `@theme/BlogListPage`.
|
||||||
- **Post pages**: `/2021/11/21/algolia-docsearch-migration`, `/2021/05/12/announcing-docusaurus-two-beta`...
|
- **Post pages**: `/2021/11/21/algolia-docsearch-migration`, `/2021/05/12/announcing-docusaurus-two-beta`...
|
||||||
- Generated from each Markdown post.
|
- Generated from each Markdown post.
|
||||||
|
|
|
@ -47,7 +47,8 @@ Accepted fields:
|
||||||
| `blogSidebarCount` | <code>number \| 'ALL'</code> | `5` | Number of blog post elements to show in the blog sidebar. `'ALL'` to show all blog posts; `0` to disable. |
|
| `blogSidebarCount` | <code>number \| 'ALL'</code> | `5` | Number of blog post elements to show in the blog sidebar. `'ALL'` to show all blog posts; `0` to disable. |
|
||||||
| `blogSidebarTitle` | `string` | `'Recent posts'` | Title of the blog sidebar. |
|
| `blogSidebarTitle` | `string` | `'Recent posts'` | Title of the blog sidebar. |
|
||||||
| `routeBasePath` | `string` | `'blog'` | URL route for the blog section of your site. **DO NOT** include a trailing slash. Use `/` to put the blog at root path. |
|
| `routeBasePath` | `string` | `'blog'` | URL route for the blog section of your site. **DO NOT** include a trailing slash. Use `/` to put the blog at root path. |
|
||||||
| `tagsBasePath` | `string` | `'tags'` | URL route for the tags section of your blog. Will be appended to `routeBasePath`. **DO NOT** include a trailing slash. |
|
| `tagsBasePath` | `string` | `'tags'` | URL route for the tags section of your blog. Will be appended to `routeBasePath`. |
|
||||||
|
| `pageBasePath` | `string` | `'page'` | URL route for the pages section of your blog. Will be appended to `routeBasePath`. |
|
||||||
| `archiveBasePath` | <code>string \| null</code> | `'archive'` | URL route for the archive section of your blog. Will be appended to `routeBasePath`. **DO NOT** include a trailing slash. Use `null` to disable generation of archive. |
|
| `archiveBasePath` | <code>string \| null</code> | `'archive'` | URL route for the archive section of your blog. Will be appended to `routeBasePath`. **DO NOT** include a trailing slash. Use `null` to disable generation of archive. |
|
||||||
| `include` | `string[]` | `['**/*.{md,mdx}']` | Array of glob patterns matching Markdown files to be built, relative to the content path. |
|
| `include` | `string[]` | `['**/*.{md,mdx}']` | Array of glob patterns matching Markdown files to be built, relative to the content path. |
|
||||||
| `exclude` | `string[]` | _See example configuration_ | Array of glob patterns matching Markdown files to be excluded. Serves as refinement based on the `include` option. |
|
| `exclude` | `string[]` | _See example configuration_ | Array of glob patterns matching Markdown files to be excluded. Serves as refinement based on the `include` option. |
|
||||||
|
|
Loading…
Add table
Reference in a new issue