mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-14 09:37:37 +02:00
feat(content-blog): Allow pagination for BlogTagsPostsPage (#6221)
Co-authored-by: Joshua Chen <sidachen2003@gmail.com> Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
This commit is contained in:
parent
01c6f15b15
commit
48f080ebca
20 changed files with 321 additions and 91 deletions
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
slug: /simple/slug/another
|
||||||
|
title: Another Simple Slug
|
||||||
|
date: 2020-08-15
|
||||||
|
|
||||||
|
author: Sébastien Lorber
|
||||||
|
author_title: Docusaurus maintainer
|
||||||
|
author_url: https://sebastienlorber.com
|
||||||
|
|
||||||
|
tags: [tag1]
|
||||||
|
---
|
||||||
|
|
||||||
|
simple url slug
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
slug: /another/tags
|
||||||
|
title: Another With Tag
|
||||||
|
date: 2020-08-15
|
||||||
|
|
||||||
|
tags: [tag1, tag2]
|
||||||
|
---
|
||||||
|
|
||||||
|
with tag
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
slug: /another/tags2
|
||||||
|
title: Another With Tag
|
||||||
|
date: 2020-08-15
|
||||||
|
|
||||||
|
tags: [tag1, tag2]
|
||||||
|
---
|
||||||
|
|
||||||
|
with tag
|
|
@ -0,0 +1,77 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`loadBlog test blog tags 1`] = `
|
||||||
|
Object {
|
||||||
|
"/blog/tags/tag-1": Object {
|
||||||
|
"items": Array [
|
||||||
|
"/simple/slug/another",
|
||||||
|
"/another/tags",
|
||||||
|
"/another/tags2",
|
||||||
|
],
|
||||||
|
"name": "tag1",
|
||||||
|
"pages": Array [
|
||||||
|
Object {
|
||||||
|
"items": Array [
|
||||||
|
"/simple/slug/another",
|
||||||
|
"/another/tags",
|
||||||
|
],
|
||||||
|
"metadata": Object {
|
||||||
|
"blogDescription": "Blog",
|
||||||
|
"blogTitle": "Blog",
|
||||||
|
"nextPage": "/blog/tags/tag-1/page/2",
|
||||||
|
"page": 1,
|
||||||
|
"permalink": "/blog/tags/tag-1",
|
||||||
|
"postsPerPage": 2,
|
||||||
|
"previousPage": null,
|
||||||
|
"totalCount": 3,
|
||||||
|
"totalPages": 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"items": Array [
|
||||||
|
"/another/tags2",
|
||||||
|
],
|
||||||
|
"metadata": Object {
|
||||||
|
"blogDescription": "Blog",
|
||||||
|
"blogTitle": "Blog",
|
||||||
|
"nextPage": null,
|
||||||
|
"page": 2,
|
||||||
|
"permalink": "/blog/tags/tag-1/page/2",
|
||||||
|
"postsPerPage": 2,
|
||||||
|
"previousPage": "/blog/tags/tag-1",
|
||||||
|
"totalCount": 3,
|
||||||
|
"totalPages": 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"permalink": "/blog/tags/tag-1",
|
||||||
|
},
|
||||||
|
"/blog/tags/tag-2": Object {
|
||||||
|
"items": Array [
|
||||||
|
"/another/tags",
|
||||||
|
"/another/tags2",
|
||||||
|
],
|
||||||
|
"name": "tag2",
|
||||||
|
"pages": Array [
|
||||||
|
Object {
|
||||||
|
"items": Array [
|
||||||
|
"/another/tags",
|
||||||
|
"/another/tags2",
|
||||||
|
],
|
||||||
|
"metadata": Object {
|
||||||
|
"blogDescription": "Blog",
|
||||||
|
"blogTitle": "Blog",
|
||||||
|
"nextPage": null,
|
||||||
|
"page": 1,
|
||||||
|
"permalink": "/blog/tags/tag-2",
|
||||||
|
"postsPerPage": 2,
|
||||||
|
"previousPage": null,
|
||||||
|
"totalCount": 2,
|
||||||
|
"totalPages": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"permalink": "/blog/tags/tag-2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
|
@ -24,6 +24,7 @@ function findByTitle(
|
||||||
): BlogPost | undefined {
|
): BlogPost | undefined {
|
||||||
return blogPosts.find((v) => v.metadata.title === title);
|
return blogPosts.find((v) => v.metadata.title === title);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getByTitle(blogPosts: BlogPost[], title: string): BlogPost {
|
function getByTitle(blogPosts: BlogPost[], title: string): BlogPost {
|
||||||
const post = findByTitle(blogPosts, title);
|
const post = findByTitle(blogPosts, title);
|
||||||
if (!post) {
|
if (!post) {
|
||||||
|
@ -99,6 +100,16 @@ describe('loadBlog', () => {
|
||||||
return blogPosts;
|
return blogPosts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getBlogTags = async (
|
||||||
|
siteDir: string,
|
||||||
|
pluginOptions: Partial<PluginOptions> = {},
|
||||||
|
i18n: I18n = DefaultI18N,
|
||||||
|
) => {
|
||||||
|
const plugin = await getPlugin(siteDir, pluginOptions, i18n);
|
||||||
|
const {blogTags} = (await plugin.loadContent!())!;
|
||||||
|
return blogTags;
|
||||||
|
};
|
||||||
|
|
||||||
test('getPathsToWatch', async () => {
|
test('getPathsToWatch', async () => {
|
||||||
const siteDir = path.join(__dirname, '__fixtures__', 'website');
|
const siteDir = path.join(__dirname, '__fixtures__', 'website');
|
||||||
const plugin = await getPlugin(siteDir);
|
const plugin = await getPlugin(siteDir);
|
||||||
|
@ -454,4 +465,18 @@ describe('loadBlog', () => {
|
||||||
reversedOrder.map((x) => x.metadata.date),
|
reversedOrder.map((x) => x.metadata.date),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('test blog tags', async () => {
|
||||||
|
const siteDir = path.join(
|
||||||
|
__dirname,
|
||||||
|
'__fixtures__',
|
||||||
|
'website-blog-with-tags',
|
||||||
|
);
|
||||||
|
const blogTags = await getBlogTags(siteDir, {
|
||||||
|
postsPerPage: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(Object.keys(blogTags).length).toEqual(2);
|
||||||
|
expect(blogTags).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,6 +14,7 @@ import type {
|
||||||
BlogContentPaths,
|
BlogContentPaths,
|
||||||
BlogMarkdownLoaderOptions,
|
BlogMarkdownLoaderOptions,
|
||||||
BlogTags,
|
BlogTags,
|
||||||
|
BlogPaginated,
|
||||||
} from './types';
|
} from './types';
|
||||||
import {
|
import {
|
||||||
parseMarkdownString,
|
parseMarkdownString,
|
||||||
|
@ -50,16 +51,79 @@ export function getSourceToPermalink(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBlogTags(blogPosts: BlogPost[]): BlogTags {
|
export function paginateBlogPosts({
|
||||||
|
blogPosts,
|
||||||
|
basePageUrl,
|
||||||
|
blogTitle,
|
||||||
|
blogDescription,
|
||||||
|
postsPerPageOption,
|
||||||
|
}: {
|
||||||
|
blogPosts: BlogPost[];
|
||||||
|
basePageUrl: string;
|
||||||
|
blogTitle: string;
|
||||||
|
blogDescription: string;
|
||||||
|
postsPerPageOption: number | 'ALL';
|
||||||
|
}): BlogPaginated[] {
|
||||||
|
const totalCount = blogPosts.length;
|
||||||
|
const postsPerPage =
|
||||||
|
postsPerPageOption === 'ALL' ? totalCount : postsPerPageOption;
|
||||||
|
const numberOfPages = Math.ceil(totalCount / postsPerPage);
|
||||||
|
|
||||||
|
const pages: BlogPaginated[] = [];
|
||||||
|
|
||||||
|
function permalink(page: number) {
|
||||||
|
return page > 0 ? `${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) : null,
|
||||||
|
nextPage: page < numberOfPages - 1 ? permalink(page + 1) : null,
|
||||||
|
blogDescription,
|
||||||
|
blogTitle,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBlogTags({
|
||||||
|
blogPosts,
|
||||||
|
...params
|
||||||
|
}: {
|
||||||
|
blogPosts: BlogPost[];
|
||||||
|
blogTitle: string;
|
||||||
|
blogDescription: string;
|
||||||
|
postsPerPageOption: number | 'ALL';
|
||||||
|
}): BlogTags {
|
||||||
const groups = groupTaggedItems(
|
const groups = groupTaggedItems(
|
||||||
blogPosts,
|
blogPosts,
|
||||||
(blogPost) => blogPost.metadata.tags,
|
(blogPost) => blogPost.metadata.tags,
|
||||||
);
|
);
|
||||||
return mapValues(groups, (group) => ({
|
|
||||||
name: group.tag.label,
|
return mapValues(groups, (group) => {
|
||||||
items: group.items.map((item) => item.id),
|
const {tag, items: tagBlogPosts} = group;
|
||||||
permalink: group.tag.permalink,
|
return {
|
||||||
}));
|
name: tag.label,
|
||||||
|
items: tagBlogPosts.map((item) => item.id),
|
||||||
|
permalink: tag.permalink,
|
||||||
|
pages: paginateBlogPosts({
|
||||||
|
blogPosts: tagBlogPosts,
|
||||||
|
basePageUrl: group.tag.permalink,
|
||||||
|
...params,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const DATE_FILENAME_REGEX =
|
const DATE_FILENAME_REGEX =
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {
|
||||||
import {translateContent, getTranslationFiles} from './translations';
|
import {translateContent, getTranslationFiles} from './translations';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
|
BlogTag,
|
||||||
BlogTags,
|
BlogTags,
|
||||||
BlogContent,
|
BlogContent,
|
||||||
BlogItemsToMetadata,
|
BlogItemsToMetadata,
|
||||||
|
@ -31,6 +32,7 @@ import type {
|
||||||
BlogContentPaths,
|
BlogContentPaths,
|
||||||
BlogMarkdownLoaderOptions,
|
BlogMarkdownLoaderOptions,
|
||||||
MetaData,
|
MetaData,
|
||||||
|
TagModule,
|
||||||
} from './types';
|
} from './types';
|
||||||
import {PluginOptionSchema} from './pluginOptionSchema';
|
import {PluginOptionSchema} from './pluginOptionSchema';
|
||||||
import type {
|
import type {
|
||||||
|
@ -46,6 +48,7 @@ import {
|
||||||
generateBlogPosts,
|
generateBlogPosts,
|
||||||
getSourceToPermalink,
|
getSourceToPermalink,
|
||||||
getBlogTags,
|
getBlogTags,
|
||||||
|
paginateBlogPosts,
|
||||||
} from './blogUtils';
|
} from './blogUtils';
|
||||||
import {createBlogFeedFiles} from './feed';
|
import {createBlogFeedFiles} from './feed';
|
||||||
import type {
|
import type {
|
||||||
|
@ -134,6 +137,7 @@ export default async function pluginContentBlog(
|
||||||
blogListPaginated: [],
|
blogListPaginated: [],
|
||||||
blogTags: {},
|
blogTags: {},
|
||||||
blogTagsListPath: null,
|
blogTagsListPath: null,
|
||||||
|
blogTagsPaginated: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,45 +161,22 @@ export default async function pluginContentBlog(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Blog pagination routes.
|
|
||||||
// Example: `/blog`, `/blog/page/1`, `/blog/page/2`
|
|
||||||
const totalCount = blogPosts.length;
|
|
||||||
const postsPerPage =
|
|
||||||
postsPerPageOption === 'ALL' ? totalCount : postsPerPageOption;
|
|
||||||
const numberOfPages = Math.ceil(totalCount / postsPerPage);
|
|
||||||
const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
|
const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
|
||||||
|
|
||||||
const blogListPaginated: BlogPaginated[] = [];
|
const blogListPaginated: BlogPaginated[] = paginateBlogPosts({
|
||||||
|
blogPosts,
|
||||||
|
blogTitle,
|
||||||
|
blogDescription,
|
||||||
|
postsPerPageOption,
|
||||||
|
basePageUrl: baseBlogUrl,
|
||||||
|
});
|
||||||
|
|
||||||
function blogPaginationPermalink(page: number) {
|
const blogTags: BlogTags = getBlogTags({
|
||||||
return page > 0
|
blogPosts,
|
||||||
? normalizeUrl([baseBlogUrl, `page/${page + 1}`])
|
postsPerPageOption,
|
||||||
: baseBlogUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let page = 0; page < numberOfPages; page += 1) {
|
|
||||||
blogListPaginated.push({
|
|
||||||
metadata: {
|
|
||||||
permalink: blogPaginationPermalink(page),
|
|
||||||
page: page + 1,
|
|
||||||
postsPerPage,
|
|
||||||
totalPages: numberOfPages,
|
|
||||||
totalCount,
|
|
||||||
previousPage: page !== 0 ? blogPaginationPermalink(page - 1) : null,
|
|
||||||
nextPage:
|
|
||||||
page < numberOfPages - 1
|
|
||||||
? blogPaginationPermalink(page + 1)
|
|
||||||
: null,
|
|
||||||
blogDescription,
|
blogDescription,
|
||||||
blogTitle,
|
blogTitle,
|
||||||
},
|
|
||||||
items: blogPosts
|
|
||||||
.slice(page * postsPerPage, (page + 1) * postsPerPage)
|
|
||||||
.map((item) => item.id),
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
const blogTags: BlogTags = getBlogTags(blogPosts);
|
|
||||||
|
|
||||||
const tagsPath = normalizeUrl([baseBlogUrl, tagsBasePath]);
|
const tagsPath = normalizeUrl([baseBlogUrl, tagsBasePath]);
|
||||||
|
|
||||||
|
@ -345,38 +326,45 @@ export default async function pluginContentBlog(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagsModule: TagsModule = {};
|
const tagsModule: TagsModule = Object.fromEntries(
|
||||||
|
Object.entries(blogTags).map(([tagKey, tag]) => {
|
||||||
await Promise.all(
|
const tagModule: TagModule = {
|
||||||
Object.keys(blogTags).map(async (tag) => {
|
|
||||||
const {name, items, permalink} = blogTags[tag];
|
|
||||||
|
|
||||||
// Refactor all this, see docs implementation
|
|
||||||
tagsModule[tag] = {
|
|
||||||
allTagsPath: blogTagsListPath,
|
allTagsPath: blogTagsListPath,
|
||||||
slug: tag,
|
slug: tagKey,
|
||||||
name,
|
name: tag.name,
|
||||||
count: items.length,
|
count: tag.items.length,
|
||||||
permalink,
|
permalink: tag.permalink,
|
||||||
};
|
};
|
||||||
|
return [tag.name, tagModule];
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
async function createTagRoutes(tag: BlogTag): Promise<void> {
|
||||||
|
await Promise.all(
|
||||||
|
tag.pages.map(async (blogPaginated) => {
|
||||||
|
const {metadata, items} = blogPaginated;
|
||||||
const tagsMetadataPath = await createData(
|
const tagsMetadataPath = await createData(
|
||||||
`${docuHash(permalink)}.json`,
|
`${docuHash(metadata.permalink)}.json`,
|
||||||
JSON.stringify(tagsModule[tag], null, 2),
|
JSON.stringify(tagsModule[tag.name], null, 2),
|
||||||
|
);
|
||||||
|
|
||||||
|
const listMetadataPath = await createData(
|
||||||
|
`${docuHash(metadata.permalink)}-list.json`,
|
||||||
|
JSON.stringify(metadata, null, 2),
|
||||||
);
|
);
|
||||||
|
|
||||||
addRoute({
|
addRoute({
|
||||||
path: permalink,
|
path: metadata.permalink,
|
||||||
component: blogTagsPostsComponent,
|
component: blogTagsPostsComponent,
|
||||||
exact: true,
|
exact: true,
|
||||||
modules: {
|
modules: {
|
||||||
sidebar: aliasedSource(sidebarProp),
|
sidebar: aliasedSource(sidebarProp),
|
||||||
items: items.map((postID) => {
|
items: items.map((postID) => {
|
||||||
const metadata = blogItemsToMetadata[postID];
|
const blogPostMetadata = blogItemsToMetadata[postID];
|
||||||
return {
|
return {
|
||||||
content: {
|
content: {
|
||||||
__import: true,
|
__import: true,
|
||||||
path: metadata.source,
|
path: blogPostMetadata.source,
|
||||||
query: {
|
query: {
|
||||||
truncated: true,
|
truncated: true,
|
||||||
},
|
},
|
||||||
|
@ -384,10 +372,14 @@ export default async function pluginContentBlog(
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
metadata: aliasedSource(tagsMetadataPath),
|
metadata: aliasedSource(tagsMetadataPath),
|
||||||
|
listMetadata: aliasedSource(listMetadataPath),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(Object.values(blogTags).map(createTagRoutes));
|
||||||
|
|
||||||
// Only create /tags page if there are tags.
|
// Only create /tags page if there are tags.
|
||||||
if (Object.keys(blogTags).length > 0) {
|
if (Object.keys(blogTags).length > 0) {
|
||||||
|
|
|
@ -259,10 +259,12 @@ declare module '@theme/BlogTagsPostsPage' {
|
||||||
import type {BlogSidebar} from '@theme/BlogSidebar';
|
import type {BlogSidebar} from '@theme/BlogSidebar';
|
||||||
import type {Tag} from '@theme/BlogTagsListPage';
|
import type {Tag} from '@theme/BlogTagsListPage';
|
||||||
import type {Content} from '@theme/BlogPostPage';
|
import type {Content} from '@theme/BlogPostPage';
|
||||||
|
import type {Metadata} from '@theme/BlogListPage';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly sidebar: BlogSidebar;
|
readonly sidebar: BlogSidebar;
|
||||||
readonly metadata: Tag;
|
readonly metadata: Tag;
|
||||||
|
readonly listMetadata: Metadata;
|
||||||
readonly items: readonly {readonly content: Content}[];
|
readonly items: readonly {readonly content: Content}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,13 +26,17 @@ export interface BlogContent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BlogTags {
|
export interface BlogTags {
|
||||||
[key: string]: BlogTag;
|
// TODO, the key is the tag slug/permalink
|
||||||
|
// This is due to legacy frontmatter: tags: [{label: "xyz", permalink: "/1"}, {label: "xyz", permalink: "/2"}
|
||||||
|
// Soon we should forbid declaring permalink through frontmatter
|
||||||
|
[tagKey: string]: BlogTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BlogTag {
|
export interface BlogTag {
|
||||||
name: string;
|
name: string;
|
||||||
items: string[];
|
items: string[]; // blog post permalinks
|
||||||
permalink: string;
|
permalink: string;
|
||||||
|
pages: BlogPaginated[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BlogPost {
|
export interface BlogPost {
|
||||||
|
@ -55,7 +59,7 @@ export interface BlogPaginatedMetadata {
|
||||||
|
|
||||||
export interface BlogPaginated {
|
export interface BlogPaginated {
|
||||||
metadata: BlogPaginatedMetadata;
|
metadata: BlogPaginatedMetadata;
|
||||||
items: string[];
|
items: string[]; // blog post permalinks
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetaData {
|
export interface MetaData {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import BlogPostItem from '@theme/BlogPostItem';
|
||||||
import type {Props} from '@theme/BlogTagsPostsPage';
|
import type {Props} from '@theme/BlogTagsPostsPage';
|
||||||
import Translate, {translate} from '@docusaurus/Translate';
|
import Translate, {translate} from '@docusaurus/Translate';
|
||||||
import {ThemeClassNames, usePluralForm} from '@docusaurus/theme-common';
|
import {ThemeClassNames, usePluralForm} from '@docusaurus/theme-common';
|
||||||
|
import BlogListPaginator from '@theme/BlogListPaginator';
|
||||||
|
|
||||||
// Very simple pluralization: probably good enough for now
|
// Very simple pluralization: probably good enough for now
|
||||||
function useBlogPostsPlural() {
|
function useBlogPostsPlural() {
|
||||||
|
@ -33,7 +34,7 @@ function useBlogPostsPlural() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function BlogTagsPostsPage(props: Props): JSX.Element {
|
export default function BlogTagsPostsPage(props: Props): JSX.Element {
|
||||||
const {metadata, items, sidebar} = props;
|
const {metadata, items, sidebar, listMetadata} = props;
|
||||||
const {allTagsPath, name: tagName, count} = metadata;
|
const {allTagsPath, name: tagName, count} = metadata;
|
||||||
const blogPostsPlural = useBlogPostsPlural();
|
const blogPostsPlural = useBlogPostsPlural();
|
||||||
const title = translate(
|
const title = translate(
|
||||||
|
@ -77,6 +78,7 @@ export default function BlogTagsPostsPage(props: Props): JSX.Element {
|
||||||
<BlogPostContent />
|
<BlogPostContent />
|
||||||
</BlogPostItem>
|
</BlogPostItem>
|
||||||
))}
|
))}
|
||||||
|
<BlogListPaginator metadata={listMetadata} />
|
||||||
</BlogLayout>
|
</BlogLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ authors:
|
||||||
- slorber
|
- slorber
|
||||||
toc_min_heading_level: 2
|
toc_min_heading_level: 2
|
||||||
toc_max_heading_level: 4
|
toc_max_heading_level: 4
|
||||||
|
tags: [paginated-tag]
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- truncate -->
|
<!-- truncate -->
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
---
|
||||||
|
tags: [paginated-tag]
|
||||||
|
---
|
||||||
|
|
||||||
# Hmmm!
|
# Hmmm!
|
||||||
|
|
||||||
This is a blog post from an anonymous author!
|
This is a blog post from an anonymous author!
|
||||||
|
|
|
@ -8,6 +8,7 @@ tags:
|
||||||
[
|
[
|
||||||
blog,
|
blog,
|
||||||
docusaurus,
|
docusaurus,
|
||||||
|
paginated-tag,
|
||||||
long,
|
long,
|
||||||
long-long,
|
long-long,
|
||||||
long-long-long,
|
long-long-long,
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
---
|
||||||
|
tags: [paginated-tag]
|
||||||
|
---
|
||||||
|
|
||||||
# Post with duplicate title
|
# Post with duplicate title
|
||||||
|
|
||||||
See https://github.com/facebook/docusaurus/issues/6059. This one and [2021-11-13-dup-title.md](./2021-11-13-dup-title.md) should both show up.
|
See https://github.com/facebook/docusaurus/issues/6059. This one and [2021-11-13-dup-title.md](./2021-11-13-dup-title.md) should both show up.
|
||||||
|
|
|
@ -2,7 +2,15 @@
|
||||||
title: Blog post MDX Feed tests
|
title: Blog post MDX Feed tests
|
||||||
authors:
|
authors:
|
||||||
- slorber
|
- slorber
|
||||||
tags: [blog, docusaurus, long-long, long-long-long, long-long-long-long]
|
tags:
|
||||||
|
[
|
||||||
|
paginated-tag,
|
||||||
|
blog,
|
||||||
|
docusaurus,
|
||||||
|
long-long,
|
||||||
|
long-long-long,
|
||||||
|
long-long-long-long,
|
||||||
|
]
|
||||||
hide_reading_time: true
|
hide_reading_time: true
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,15 @@
|
||||||
title: Blog post MDX require Feed tests
|
title: Blog post MDX require Feed tests
|
||||||
authors:
|
authors:
|
||||||
- slorber
|
- slorber
|
||||||
tags: [blog, docusaurus, long-long, long-long-long, long-long-long-long]
|
tags:
|
||||||
|
[
|
||||||
|
paginated-tag,
|
||||||
|
blog,
|
||||||
|
docusaurus,
|
||||||
|
long-long,
|
||||||
|
long-long-long,
|
||||||
|
long-long-long-long,
|
||||||
|
]
|
||||||
---
|
---
|
||||||
|
|
||||||
Some MDX tests, mostly to test how the RSS feed render those
|
Some MDX tests, mostly to test how the RSS feed render those
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
---
|
||||||
|
tags: [paginated-tag]
|
||||||
|
---
|
||||||
|
|
||||||
# Post with duplicate title
|
# Post with duplicate title
|
||||||
|
|
||||||
I hope I'm still here
|
I hope I'm still here
|
||||||
|
|
|
@ -40,6 +40,7 @@ authors:
|
||||||
url: https://github.com/anshulrgoyal
|
url: https://github.com/anshulrgoyal
|
||||||
- image_url: https://github.com/italicize.png
|
- image_url: https://github.com/italicize.png
|
||||||
url: https://github.com/italicize
|
url: https://github.com/italicize
|
||||||
|
tags: [paginated-tag]
|
||||||
---
|
---
|
||||||
|
|
||||||
# Image-only authors
|
# Image-only authors
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
title: Using twice the blog plugin
|
title: Using twice the blog plugin
|
||||||
authors: [slorber]
|
authors: [slorber]
|
||||||
tags: [blog, docusaurus]
|
tags: [paginated-tag, blog, docusaurus]
|
||||||
---
|
---
|
||||||
|
|
||||||
Did you know you can use multiple instances of the same plugin?
|
Did you know you can use multiple instances of the same plugin?
|
||||||
|
|
|
@ -116,7 +116,8 @@ const config = {
|
||||||
require.resolve('./src/plugins/changelog/index.js'),
|
require.resolve('./src/plugins/changelog/index.js'),
|
||||||
{
|
{
|
||||||
blogTitle: 'Docusaurus changelog',
|
blogTitle: 'Docusaurus changelog',
|
||||||
blogDescription: 'Keep yourself up-to-date about new features in every release',
|
blogDescription:
|
||||||
|
'Keep yourself up-to-date about new features in every release',
|
||||||
blogSidebarCount: 'ALL',
|
blogSidebarCount: 'ALL',
|
||||||
blogSidebarTitle: 'Changelog',
|
blogSidebarTitle: 'Changelog',
|
||||||
routeBasePath: '/changelog',
|
routeBasePath: '/changelog',
|
||||||
|
@ -127,10 +128,11 @@ const config = {
|
||||||
feedOptions: {
|
feedOptions: {
|
||||||
type: 'all',
|
type: 'all',
|
||||||
title: 'Docusaurus changelog',
|
title: 'Docusaurus changelog',
|
||||||
description: 'Keep yourself up-to-date about new features in every release',
|
description:
|
||||||
|
'Keep yourself up-to-date about new features in every release',
|
||||||
copyright: `Copyright © ${new Date().getFullYear()} Facebook, Inc.`,
|
copyright: `Copyright © ${new Date().getFullYear()} Facebook, Inc.`,
|
||||||
language: 'en',
|
language: 'en',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue