mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-19 20:17:06 +02:00
refactor(content-blog): clean up type definitions; in-code documentation (#6922)
* refactor(content-blog): clean up type definitions; in-code documentation * add doc
This commit is contained in:
parent
46b1027c4a
commit
8d1c1954c1
16 changed files with 509 additions and 240 deletions
|
@ -37,7 +37,7 @@ exports[`paginateBlogPosts generates right pages 1`] = `
|
||||||
"page": 1,
|
"page": 1,
|
||||||
"permalink": "/blog",
|
"permalink": "/blog",
|
||||||
"postsPerPage": 2,
|
"postsPerPage": 2,
|
||||||
"previousPage": null,
|
"previousPage": undefined,
|
||||||
"totalCount": 5,
|
"totalCount": 5,
|
||||||
"totalPages": 3,
|
"totalPages": 3,
|
||||||
},
|
},
|
||||||
|
@ -66,7 +66,7 @@ exports[`paginateBlogPosts generates right pages 1`] = `
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"blogDescription": "Blog Description",
|
"blogDescription": "Blog Description",
|
||||||
"blogTitle": "Blog Title",
|
"blogTitle": "Blog Title",
|
||||||
"nextPage": null,
|
"nextPage": undefined,
|
||||||
"page": 3,
|
"page": 3,
|
||||||
"permalink": "/blog/page/3",
|
"permalink": "/blog/page/3",
|
||||||
"postsPerPage": 2,
|
"postsPerPage": 2,
|
||||||
|
@ -92,7 +92,7 @@ exports[`paginateBlogPosts generates right pages 2`] = `
|
||||||
"page": 1,
|
"page": 1,
|
||||||
"permalink": "/",
|
"permalink": "/",
|
||||||
"postsPerPage": 2,
|
"postsPerPage": 2,
|
||||||
"previousPage": null,
|
"previousPage": undefined,
|
||||||
"totalCount": 5,
|
"totalCount": 5,
|
||||||
"totalPages": 3,
|
"totalPages": 3,
|
||||||
},
|
},
|
||||||
|
@ -121,7 +121,7 @@ exports[`paginateBlogPosts generates right pages 2`] = `
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"blogDescription": "Blog Description",
|
"blogDescription": "Blog Description",
|
||||||
"blogTitle": "Blog Title",
|
"blogTitle": "Blog Title",
|
||||||
"nextPage": null,
|
"nextPage": undefined,
|
||||||
"page": 3,
|
"page": 3,
|
||||||
"permalink": "/page/3",
|
"permalink": "/page/3",
|
||||||
"postsPerPage": 2,
|
"postsPerPage": 2,
|
||||||
|
@ -146,11 +146,11 @@ exports[`paginateBlogPosts generates right pages 3`] = `
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"blogDescription": "Blog Description",
|
"blogDescription": "Blog Description",
|
||||||
"blogTitle": "Blog Title",
|
"blogTitle": "Blog Title",
|
||||||
"nextPage": null,
|
"nextPage": undefined,
|
||||||
"page": 1,
|
"page": 1,
|
||||||
"permalink": "/",
|
"permalink": "/",
|
||||||
"postsPerPage": 10,
|
"postsPerPage": 10,
|
||||||
"previousPage": null,
|
"previousPage": undefined,
|
||||||
"totalCount": 5,
|
"totalCount": 5,
|
||||||
"totalPages": 1,
|
"totalPages": 1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -182,6 +182,7 @@ exports[`rss has feed item for each post 1`] = `
|
||||||
<lastBuildDate>Sat, 06 Mar 2021 00:00:00 GMT</lastBuildDate>
|
<lastBuildDate>Sat, 06 Mar 2021 00:00:00 GMT</lastBuildDate>
|
||||||
<docs>https://validator.w3.org/feed/docs/rss2.html</docs>
|
<docs>https://validator.w3.org/feed/docs/rss2.html</docs>
|
||||||
<generator>https://github.com/jpmonette/feed</generator>
|
<generator>https://github.com/jpmonette/feed</generator>
|
||||||
|
<language>en</language>
|
||||||
<copyright>Copyright</copyright>
|
<copyright>Copyright</copyright>
|
||||||
<item>
|
<item>
|
||||||
<title><![CDATA[MDX Blog Sample with require calls]]></title>
|
<title><![CDATA[MDX Blog Sample with require calls]]></title>
|
||||||
|
|
|
@ -19,11 +19,11 @@ exports[`blog plugin works on blog tags without pagination 1`] = `
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"blogDescription": "Blog",
|
"blogDescription": "Blog",
|
||||||
"blogTitle": "Blog",
|
"blogTitle": "Blog",
|
||||||
"nextPage": null,
|
"nextPage": undefined,
|
||||||
"page": 1,
|
"page": 1,
|
||||||
"permalink": "/blog/tags/tag-1",
|
"permalink": "/blog/tags/tag-1",
|
||||||
"postsPerPage": 3,
|
"postsPerPage": 3,
|
||||||
"previousPage": null,
|
"previousPage": undefined,
|
||||||
"totalCount": 3,
|
"totalCount": 3,
|
||||||
"totalPages": 1,
|
"totalPages": 1,
|
||||||
},
|
},
|
||||||
|
@ -46,11 +46,11 @@ exports[`blog plugin works on blog tags without pagination 1`] = `
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"blogDescription": "Blog",
|
"blogDescription": "Blog",
|
||||||
"blogTitle": "Blog",
|
"blogTitle": "Blog",
|
||||||
"nextPage": null,
|
"nextPage": undefined,
|
||||||
"page": 1,
|
"page": 1,
|
||||||
"permalink": "/blog/tags/tag-2",
|
"permalink": "/blog/tags/tag-2",
|
||||||
"postsPerPage": 2,
|
"postsPerPage": 2,
|
||||||
"previousPage": null,
|
"previousPage": undefined,
|
||||||
"totalCount": 2,
|
"totalCount": 2,
|
||||||
"totalPages": 1,
|
"totalPages": 1,
|
||||||
},
|
},
|
||||||
|
@ -83,7 +83,7 @@ exports[`blog plugin works with blog tags 1`] = `
|
||||||
"page": 1,
|
"page": 1,
|
||||||
"permalink": "/blog/tags/tag-1",
|
"permalink": "/blog/tags/tag-1",
|
||||||
"postsPerPage": 2,
|
"postsPerPage": 2,
|
||||||
"previousPage": null,
|
"previousPage": undefined,
|
||||||
"totalCount": 3,
|
"totalCount": 3,
|
||||||
"totalPages": 2,
|
"totalPages": 2,
|
||||||
},
|
},
|
||||||
|
@ -95,7 +95,7 @@ exports[`blog plugin works with blog tags 1`] = `
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"blogDescription": "Blog",
|
"blogDescription": "Blog",
|
||||||
"blogTitle": "Blog",
|
"blogTitle": "Blog",
|
||||||
"nextPage": null,
|
"nextPage": undefined,
|
||||||
"page": 2,
|
"page": 2,
|
||||||
"permalink": "/blog/tags/tag-1/page/2",
|
"permalink": "/blog/tags/tag-1/page/2",
|
||||||
"postsPerPage": 2,
|
"postsPerPage": 2,
|
||||||
|
@ -122,11 +122,11 @@ exports[`blog plugin works with blog tags 1`] = `
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"blogDescription": "Blog",
|
"blogDescription": "Blog",
|
||||||
"blogTitle": "Blog",
|
"blogTitle": "Blog",
|
||||||
"nextPage": null,
|
"nextPage": undefined,
|
||||||
"page": 1,
|
"page": 1,
|
||||||
"permalink": "/blog/tags/tag-2",
|
"permalink": "/blog/tags/tag-2",
|
||||||
"postsPerPage": 2,
|
"postsPerPage": 2,
|
||||||
"previousPage": null,
|
"previousPage": undefined,
|
||||||
"totalCount": 2,
|
"totalCount": 2,
|
||||||
"totalPages": 1,
|
"totalPages": 1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -32,11 +32,11 @@ exports[`translateContent falls back when translation is incomplete 1`] = `
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"blogDescription": "Someone's random blog",
|
"blogDescription": "Someone's random blog",
|
||||||
"blogTitle": "My blog",
|
"blogTitle": "My blog",
|
||||||
"nextPage": null,
|
"nextPage": undefined,
|
||||||
"page": 1,
|
"page": 1,
|
||||||
"permalink": "/",
|
"permalink": "/",
|
||||||
"postsPerPage": 10,
|
"postsPerPage": 10,
|
||||||
"previousPage": null,
|
"previousPage": undefined,
|
||||||
"totalCount": 1,
|
"totalCount": 1,
|
||||||
"totalPages": 1,
|
"totalPages": 1,
|
||||||
},
|
},
|
||||||
|
@ -73,11 +73,11 @@ exports[`translateContent returns translated loaded 1`] = `
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"blogDescription": "Someone's random blog (translated)",
|
"blogDescription": "Someone's random blog (translated)",
|
||||||
"blogTitle": "My blog (translated)",
|
"blogTitle": "My blog (translated)",
|
||||||
"nextPage": null,
|
"nextPage": undefined,
|
||||||
"page": 1,
|
"page": 1,
|
||||||
"permalink": "/",
|
"permalink": "/",
|
||||||
"postsPerPage": 10,
|
"postsPerPage": 10,
|
||||||
"previousPage": null,
|
"previousPage": undefined,
|
||||||
"totalCount": 1,
|
"totalCount": 1,
|
||||||
"totalPages": 1,
|
"totalPages": 1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -49,6 +49,7 @@ async function testGenerateFeeds(
|
||||||
options,
|
options,
|
||||||
siteConfig: context.siteConfig,
|
siteConfig: context.siteConfig,
|
||||||
outDir: context.outDir,
|
outDir: context.outDir,
|
||||||
|
locale: 'en',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,8 @@ const sampleBlogContent: BlogContent = {
|
||||||
postsPerPage: 10,
|
postsPerPage: 10,
|
||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
totalCount: 1,
|
totalCount: 1,
|
||||||
previousPage: null,
|
previousPage: undefined,
|
||||||
nextPage: null,
|
nextPage: undefined,
|
||||||
blogTitle: sampleBlogOptions.blogTitle,
|
blogTitle: sampleBlogOptions.blogTitle,
|
||||||
blogDescription: sampleBlogOptions.blogDescription,
|
blogDescription: sampleBlogOptions.blogDescription,
|
||||||
},
|
},
|
||||||
|
|
|
@ -70,7 +70,7 @@ type AuthorsParam = {
|
||||||
// We may want to deprecate those in favor of using only frontMatter.authors
|
// We may want to deprecate those in favor of using only frontMatter.authors
|
||||||
function getFrontMatterAuthorLegacy(
|
function getFrontMatterAuthorLegacy(
|
||||||
frontMatter: BlogPostFrontMatter,
|
frontMatter: BlogPostFrontMatter,
|
||||||
): BlogPostFrontMatterAuthor | undefined {
|
): Author | undefined {
|
||||||
const name = frontMatter.author;
|
const name = frontMatter.author;
|
||||||
const title = frontMatter.author_title ?? frontMatter.authorTitle;
|
const title = frontMatter.author_title ?? frontMatter.authorTitle;
|
||||||
const url = frontMatter.author_url ?? frontMatter.authorURL;
|
const url = frontMatter.author_url ?? frontMatter.authorURL;
|
||||||
|
@ -92,7 +92,7 @@ function normalizeFrontMatterAuthors(
|
||||||
frontMatterAuthors: BlogPostFrontMatterAuthors = [],
|
frontMatterAuthors: BlogPostFrontMatterAuthors = [],
|
||||||
): BlogPostFrontMatterAuthor[] {
|
): BlogPostFrontMatterAuthor[] {
|
||||||
function normalizeAuthor(
|
function normalizeAuthor(
|
||||||
authorInput: string | BlogPostFrontMatterAuthor,
|
authorInput: string | Author,
|
||||||
): BlogPostFrontMatterAuthor {
|
): BlogPostFrontMatterAuthor {
|
||||||
if (typeof authorInput === 'string') {
|
if (typeof authorInput === 'string') {
|
||||||
// Technically, we could allow users to provide an author's name here, but
|
// Technically, we could allow users to provide an author's name here, but
|
||||||
|
|
|
@ -88,8 +88,8 @@ export function paginateBlogPosts({
|
||||||
postsPerPage,
|
postsPerPage,
|
||||||
totalPages: numberOfPages,
|
totalPages: numberOfPages,
|
||||||
totalCount,
|
totalCount,
|
||||||
previousPage: page !== 0 ? permalink(page - 1) : null,
|
previousPage: page !== 0 ? permalink(page - 1) : undefined,
|
||||||
nextPage: page < numberOfPages - 1 ? permalink(page + 1) : null,
|
nextPage: page < numberOfPages - 1 ? permalink(page + 1) : undefined,
|
||||||
blogDescription,
|
blogDescription,
|
||||||
blogTitle,
|
blogTitle,
|
||||||
},
|
},
|
||||||
|
|
|
@ -29,11 +29,13 @@ async function generateBlogFeed({
|
||||||
options,
|
options,
|
||||||
siteConfig,
|
siteConfig,
|
||||||
outDir,
|
outDir,
|
||||||
|
locale,
|
||||||
}: {
|
}: {
|
||||||
blogPosts: BlogPost[];
|
blogPosts: BlogPost[];
|
||||||
options: PluginOptions;
|
options: PluginOptions;
|
||||||
siteConfig: DocusaurusConfig;
|
siteConfig: DocusaurusConfig;
|
||||||
outDir: string;
|
outDir: string;
|
||||||
|
locale: string;
|
||||||
}): Promise<Feed | null> {
|
}): Promise<Feed | null> {
|
||||||
if (!blogPosts.length) {
|
if (!blogPosts.length) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -47,11 +49,11 @@ async function generateBlogFeed({
|
||||||
|
|
||||||
const feed = new Feed({
|
const feed = new Feed({
|
||||||
id: blogBaseUrl,
|
id: blogBaseUrl,
|
||||||
title: feedOptions.title || `${title} Blog`,
|
title: feedOptions.title ?? `${title} Blog`,
|
||||||
updated,
|
updated,
|
||||||
language: feedOptions.language,
|
language: feedOptions.language ?? locale,
|
||||||
link: blogBaseUrl,
|
link: blogBaseUrl,
|
||||||
description: feedOptions.description || `${siteConfig.title} Blog`,
|
description: feedOptions.description ?? `${siteConfig.title} Blog`,
|
||||||
favicon: favicon ? normalizeUrl([siteUrl, baseUrl, favicon]) : undefined,
|
favicon: favicon ? normalizeUrl([siteUrl, baseUrl, favicon]) : undefined,
|
||||||
copyright: feedOptions.copyright,
|
copyright: feedOptions.copyright,
|
||||||
});
|
});
|
||||||
|
@ -140,17 +142,20 @@ export async function createBlogFeedFiles({
|
||||||
options,
|
options,
|
||||||
siteConfig,
|
siteConfig,
|
||||||
outDir,
|
outDir,
|
||||||
|
locale,
|
||||||
}: {
|
}: {
|
||||||
blogPosts: BlogPost[];
|
blogPosts: BlogPost[];
|
||||||
options: PluginOptions;
|
options: PluginOptions;
|
||||||
siteConfig: DocusaurusConfig;
|
siteConfig: DocusaurusConfig;
|
||||||
outDir: string;
|
outDir: string;
|
||||||
|
locale: string;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const feed = await generateBlogFeed({
|
const feed = await generateBlogFeed({
|
||||||
blogPosts,
|
blogPosts,
|
||||||
options,
|
options,
|
||||||
siteConfig,
|
siteConfig,
|
||||||
outDir,
|
outDir,
|
||||||
|
locale,
|
||||||
});
|
});
|
||||||
|
|
||||||
const feedTypes = options.feedOptions.type;
|
const feedTypes = options.feedOptions.type;
|
||||||
|
|
|
@ -26,13 +26,9 @@ import type {
|
||||||
BlogTag,
|
BlogTag,
|
||||||
BlogTags,
|
BlogTags,
|
||||||
BlogContent,
|
BlogContent,
|
||||||
BlogItemsToMetadata,
|
|
||||||
TagsModule,
|
|
||||||
BlogPaginated,
|
BlogPaginated,
|
||||||
BlogContentPaths,
|
BlogContentPaths,
|
||||||
BlogMarkdownLoaderOptions,
|
BlogMarkdownLoaderOptions,
|
||||||
MetaData,
|
|
||||||
TagModule,
|
|
||||||
} from './types';
|
} from './types';
|
||||||
import {PluginOptionSchema} from './pluginOptionSchema';
|
import {PluginOptionSchema} from './pluginOptionSchema';
|
||||||
import type {
|
import type {
|
||||||
|
@ -52,7 +48,9 @@ import {createBlogFeedFiles} from './feed';
|
||||||
import type {
|
import type {
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
BlogPostFrontMatter,
|
BlogPostFrontMatter,
|
||||||
|
BlogPostMetadata,
|
||||||
Assets,
|
Assets,
|
||||||
|
TagModule,
|
||||||
} from '@docusaurus/plugin-content-blog';
|
} from '@docusaurus/plugin-content-blog';
|
||||||
|
|
||||||
export default async function pluginContentBlog(
|
export default async function pluginContentBlog(
|
||||||
|
@ -214,7 +212,7 @@ export default async function pluginContentBlog(
|
||||||
blogTagsListPath,
|
blogTagsListPath,
|
||||||
} = blogContents;
|
} = blogContents;
|
||||||
|
|
||||||
const blogItemsToMetadata: BlogItemsToMetadata = {};
|
const blogItemsToMetadata: Record<string, BlogPostMetadata> = {};
|
||||||
|
|
||||||
const sidebarBlogPosts =
|
const sidebarBlogPosts =
|
||||||
options.blogSidebarCount === 'ALL'
|
options.blogSidebarCount === 'ALL'
|
||||||
|
@ -325,11 +323,10 @@ export default async function pluginContentBlog(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagsModule: TagsModule = Object.fromEntries(
|
const tagsModule: Record<string, TagModule> = Object.fromEntries(
|
||||||
Object.entries(blogTags).map(([tagKey, tag]) => {
|
Object.entries(blogTags).map(([, tag]) => {
|
||||||
const tagModule: TagModule = {
|
const tagModule: TagModule = {
|
||||||
allTagsPath: blogTagsListPath,
|
allTagsPath: blogTagsListPath,
|
||||||
slug: tagKey,
|
|
||||||
name: tag.name,
|
name: tag.name,
|
||||||
count: tag.items.length,
|
count: tag.items.length,
|
||||||
permalink: tag.permalink,
|
permalink: tag.permalink,
|
||||||
|
@ -479,7 +476,7 @@ export default async function pluginContentBlog(
|
||||||
metadata,
|
metadata,
|
||||||
}: {
|
}: {
|
||||||
frontMatter: BlogPostFrontMatter;
|
frontMatter: BlogPostFrontMatter;
|
||||||
metadata: MetaData;
|
metadata: BlogPostMetadata;
|
||||||
}): Assets => ({
|
}): Assets => ({
|
||||||
image: frontMatter.image,
|
image: frontMatter.image,
|
||||||
authorsImageUrls: metadata.authors.map(
|
authorsImageUrls: metadata.authors.map(
|
||||||
|
@ -512,6 +509,7 @@ export default async function pluginContentBlog(
|
||||||
options,
|
options,
|
||||||
outDir,
|
outDir,
|
||||||
siteConfig,
|
siteConfig,
|
||||||
|
locale: currentLocale,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -11,184 +11,487 @@ declare module '@docusaurus/plugin-content-blog' {
|
||||||
import type {Overwrite} from 'utility-types';
|
import type {Overwrite} from 'utility-types';
|
||||||
|
|
||||||
export interface Assets {
|
export interface Assets {
|
||||||
|
/**
|
||||||
|
* If `metadata.image` is a collocated image path, this entry will be the
|
||||||
|
* bundler-generated image path. Otherwise, it's empty, and the image URL
|
||||||
|
* should be accessed through `frontMatter.image`.
|
||||||
|
*/
|
||||||
image?: string;
|
image?: string;
|
||||||
authorsImageUrls: (string | undefined)[]; // Array of same size as the original MetaData.authors array
|
/**
|
||||||
|
* Array where each item is 1-1 correlated with the `metadata.authors` array
|
||||||
|
* so that client can render the correct author images. If the author's
|
||||||
|
* image is a local file path, the slot will be filled with the bundler-
|
||||||
|
* generated image path; otherwise, it's empty, and the author's image URL
|
||||||
|
* should be accessed through `authors.imageURL`.
|
||||||
|
*/
|
||||||
|
authorsImageUrls: (string | undefined)[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// We allow passing custom fields to authors, e.g., twitter
|
/**
|
||||||
|
* Unknown keys are allowed, so that we can pass custom fields to authors,
|
||||||
|
* e.g., `twitter`.
|
||||||
|
*/
|
||||||
export interface Author extends Record<string, unknown> {
|
export interface Author extends Record<string, unknown> {
|
||||||
|
/**
|
||||||
|
* If `name` doesn't exist, an `imageURL` is expected.
|
||||||
|
*/
|
||||||
name?: string;
|
name?: string;
|
||||||
|
/**
|
||||||
|
* The image path could be collocated, in which case
|
||||||
|
* `metadata.assets.authorsImageUrls` should be used instead. If `imageURL`
|
||||||
|
* doesn't exist, a `name` is expected.
|
||||||
|
*/
|
||||||
imageURL?: string;
|
imageURL?: string;
|
||||||
|
/**
|
||||||
|
* Used to generate the author's link.
|
||||||
|
*/
|
||||||
url?: string;
|
url?: string;
|
||||||
|
/**
|
||||||
|
* Used as a subtitle for the author, e.g. "maintainer of Docusaurus"
|
||||||
|
*/
|
||||||
title?: string;
|
title?: string;
|
||||||
|
/**
|
||||||
|
* Mainly used for RSS feeds; if `url` doesn't exist, `email` can be used
|
||||||
|
* to generate a fallback `mailto:` URL.
|
||||||
|
*/
|
||||||
email?: string;
|
email?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Everything is partial/unnormalized, because front matter is always
|
||||||
|
* preserved as-is. Default values will be applied when generating metadata
|
||||||
|
*/
|
||||||
export type BlogPostFrontMatter = {
|
export type BlogPostFrontMatter = {
|
||||||
|
/**
|
||||||
|
* @deprecated Use `slug` instead.
|
||||||
|
*/
|
||||||
id?: string;
|
id?: string;
|
||||||
|
/**
|
||||||
|
* Will override the default title collected from h1 heading.
|
||||||
|
* @see {@link BlogPostMetadata.title}
|
||||||
|
*/
|
||||||
title?: string;
|
title?: string;
|
||||||
|
/**
|
||||||
|
* Will override the default excerpt.
|
||||||
|
* @see {@link BlogPostMetadata.description}
|
||||||
|
*/
|
||||||
description?: string;
|
description?: string;
|
||||||
|
/**
|
||||||
|
* Front matter tags, unnormalized.
|
||||||
|
* @see {@link BlogPostMetadata.tags}
|
||||||
|
*/
|
||||||
tags?: FrontMatterTag[];
|
tags?: FrontMatterTag[];
|
||||||
|
/**
|
||||||
|
* Custom slug appended after /<baseUrl>/<routeBasePath>/
|
||||||
|
* @see {@link BlogPostMetadata.slug}
|
||||||
|
*/
|
||||||
slug?: string;
|
slug?: string;
|
||||||
|
/**
|
||||||
|
* Marks the post as draft and excludes it from the production build.
|
||||||
|
*/
|
||||||
draft?: boolean;
|
draft?: boolean;
|
||||||
date?: Date | string; // Yaml automatically convert some string patterns as Date, but not all
|
/**
|
||||||
|
* Will override the default publish date inferred from git/filename. Yaml
|
||||||
|
* only converts standard yyyy-MM-dd format to dates, so this may stay as a
|
||||||
|
* plain string.
|
||||||
|
* @see {@link BlogPostMetadata.date}
|
||||||
|
*/
|
||||||
|
date?: Date | string;
|
||||||
|
/**
|
||||||
|
* Authors, unnormalized.
|
||||||
|
* @see {@link BlogPostMetadata.authors}
|
||||||
|
*/
|
||||||
authors?: BlogPostFrontMatterAuthors;
|
authors?: BlogPostFrontMatterAuthors;
|
||||||
|
/**
|
||||||
// We may want to deprecate those older author front matter fields later:
|
* To be deprecated
|
||||||
|
* @see {@link BlogPostFrontMatterAuthor.name}
|
||||||
|
*/
|
||||||
author?: string;
|
author?: string;
|
||||||
|
/**
|
||||||
|
* To be deprecated
|
||||||
|
* @see {@link BlogPostFrontMatterAuthor.title}
|
||||||
|
*/
|
||||||
author_title?: string;
|
author_title?: string;
|
||||||
|
/**
|
||||||
|
* To be deprecated
|
||||||
|
* @see {@link BlogPostFrontMatterAuthor.url}
|
||||||
|
*/
|
||||||
author_url?: string;
|
author_url?: string;
|
||||||
|
/**
|
||||||
|
* To be deprecated
|
||||||
|
* @see {@link BlogPostFrontMatterAuthor.imageURL}
|
||||||
|
*/
|
||||||
author_image_url?: string;
|
author_image_url?: string;
|
||||||
|
|
||||||
/** @deprecated */
|
/** @deprecated v1 legacy */
|
||||||
authorTitle?: string;
|
authorTitle?: string;
|
||||||
/** @deprecated */
|
/** @deprecated v1 legacy */
|
||||||
authorURL?: string;
|
authorURL?: string;
|
||||||
/** @deprecated */
|
/** @deprecated v1 legacy */
|
||||||
authorImageURL?: string;
|
authorImageURL?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see {@link BlogPostMetadata.image}
|
||||||
|
*/
|
||||||
image?: string;
|
image?: string;
|
||||||
|
/**
|
||||||
|
* Used in the head meta
|
||||||
|
*/
|
||||||
keywords?: string[];
|
keywords?: string[];
|
||||||
|
/**
|
||||||
|
* Hide the right TOC
|
||||||
|
*/
|
||||||
hide_table_of_contents?: boolean;
|
hide_table_of_contents?: boolean;
|
||||||
|
/**
|
||||||
|
* Minimum TOC heading level
|
||||||
|
*/
|
||||||
toc_min_heading_level?: number;
|
toc_min_heading_level?: number;
|
||||||
|
/**
|
||||||
|
* Maximum TOC heading level
|
||||||
|
*/
|
||||||
toc_max_heading_level?: number;
|
toc_max_heading_level?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BlogPostFrontMatterAuthor = Record<string, unknown> & {
|
export type BlogPostFrontMatterAuthor = Author & {
|
||||||
|
/**
|
||||||
|
* Will be normalized into the `imageURL` prop.
|
||||||
|
*/
|
||||||
|
image_url?: string;
|
||||||
|
/**
|
||||||
|
* References an existing author in the authors map.
|
||||||
|
*/
|
||||||
key?: string;
|
key?: string;
|
||||||
name?: string;
|
|
||||||
imageURL?: string;
|
|
||||||
url?: string;
|
|
||||||
title?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// All the possible variants that the user can use for convenience
|
/**
|
||||||
|
* Blog post authors can be declared in front matter as a string key
|
||||||
|
* (referencing an author in authors map), an object (partially overriding the
|
||||||
|
* data in authors map, or a completely new author), or an array of a mix of
|
||||||
|
* both.
|
||||||
|
*/
|
||||||
export type BlogPostFrontMatterAuthors =
|
export type BlogPostFrontMatterAuthors =
|
||||||
| string
|
| string
|
||||||
| BlogPostFrontMatterAuthor
|
| BlogPostFrontMatterAuthor
|
||||||
| (string | BlogPostFrontMatterAuthor)[];
|
| (string | BlogPostFrontMatterAuthor)[];
|
||||||
|
|
||||||
export type EditUrlFunction = (editUrlParams: {
|
export type BlogPostMetadata = {
|
||||||
blogDirPath: string;
|
/**
|
||||||
blogPath: string;
|
* Path to the Markdown source, with `@site` alias.
|
||||||
permalink: string;
|
*/
|
||||||
locale: string;
|
readonly source: string;
|
||||||
}) => string | undefined;
|
/**
|
||||||
|
* Used to generate the page h1 heading, tab title, and pagination title.
|
||||||
export type FeedType = 'rss' | 'atom' | 'json';
|
*/
|
||||||
export type FeedOptions = {
|
|
||||||
type?: FeedType[] | null;
|
|
||||||
title?: string;
|
|
||||||
description?: string;
|
|
||||||
copyright: string;
|
|
||||||
language?: string;
|
|
||||||
};
|
|
||||||
// Feed options, as provided by user config
|
|
||||||
export type UserFeedOptions = Overwrite<
|
|
||||||
Partial<FeedOptions>,
|
|
||||||
{type?: FeedOptions['type'] | 'all'} // Handle the type: "all" shortcut
|
|
||||||
>;
|
|
||||||
|
|
||||||
// Duplicate from ngryman/reading-time to keep stability of API
|
|
||||||
type ReadingTimeOptions = {
|
|
||||||
wordsPerMinute?: number;
|
|
||||||
wordBound?: (char: string) => boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ReadingTimeFunction = (params: {
|
|
||||||
content: string;
|
|
||||||
frontMatter?: BlogPostFrontMatter & Record<string, unknown>;
|
|
||||||
options?: ReadingTimeOptions;
|
|
||||||
}) => number;
|
|
||||||
|
|
||||||
export type ReadingTimeFunctionOption = (
|
|
||||||
params: Required<Omit<Parameters<ReadingTimeFunction>[0], 'options'>> & {
|
|
||||||
defaultReadingTime: ReadingTimeFunction;
|
|
||||||
},
|
|
||||||
) => number | undefined;
|
|
||||||
|
|
||||||
export type PluginOptions = RemarkAndRehypePluginOptions & {
|
|
||||||
id?: string;
|
|
||||||
path: string;
|
|
||||||
routeBasePath: string;
|
|
||||||
tagsBasePath: string;
|
|
||||||
archiveBasePath: string | null;
|
|
||||||
include: string[];
|
|
||||||
exclude: string[];
|
|
||||||
postsPerPage: number | 'ALL';
|
|
||||||
blogListComponent: string;
|
|
||||||
blogPostComponent: string;
|
|
||||||
blogTagsListComponent: string;
|
|
||||||
blogTagsPostsComponent: string;
|
|
||||||
blogArchiveComponent: string;
|
|
||||||
blogTitle: string;
|
|
||||||
blogDescription: string;
|
|
||||||
blogSidebarCount: number | 'ALL';
|
|
||||||
blogSidebarTitle: string;
|
|
||||||
truncateMarker: RegExp;
|
|
||||||
showReadingTime: boolean;
|
|
||||||
feedOptions: {
|
|
||||||
type?: FeedType[] | null;
|
|
||||||
title?: string;
|
|
||||||
description?: string;
|
|
||||||
copyright: string;
|
|
||||||
language?: string;
|
|
||||||
};
|
|
||||||
editUrl?: string | EditUrlFunction;
|
|
||||||
editLocalizedFiles?: boolean;
|
|
||||||
admonitions: Record<string, unknown>;
|
|
||||||
authorsMapPath: string;
|
|
||||||
readingTime: ReadingTimeFunctionOption;
|
|
||||||
sortPosts: 'ascending' | 'descending';
|
|
||||||
};
|
|
||||||
// Options, as provided in the user config (before normalization)
|
|
||||||
export type Options = Overwrite<
|
|
||||||
Partial<PluginOptions>,
|
|
||||||
{feedOptions?: UserFeedOptions}
|
|
||||||
>;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/BlogPostPage' {
|
|
||||||
import type {BlogSidebar} from '@theme/BlogSidebar';
|
|
||||||
import type {TOCItem} from '@docusaurus/types';
|
|
||||||
import type {
|
|
||||||
BlogPostFrontMatter,
|
|
||||||
Author,
|
|
||||||
Assets,
|
|
||||||
} from '@docusaurus/plugin-content-blog';
|
|
||||||
|
|
||||||
export type FrontMatter = BlogPostFrontMatter;
|
|
||||||
|
|
||||||
export type Metadata = {
|
|
||||||
readonly title: string;
|
readonly title: string;
|
||||||
readonly date: string;
|
/**
|
||||||
|
* The publish date of the post. On client side, this will be serialized
|
||||||
|
* into a string.
|
||||||
|
*/
|
||||||
|
readonly date: Date;
|
||||||
|
/**
|
||||||
|
* Publish date formatted according to the locale, so that the client can
|
||||||
|
* render the date regardless of the existence of `Intl.DateTimeFormat`.
|
||||||
|
*/
|
||||||
readonly formattedDate: string;
|
readonly formattedDate: string;
|
||||||
|
/**
|
||||||
|
* Full link including base URL.
|
||||||
|
*/
|
||||||
readonly permalink: string;
|
readonly permalink: string;
|
||||||
readonly description?: string;
|
/**
|
||||||
|
* Description used in the meta. Could be an empty string (empty content)
|
||||||
|
*/
|
||||||
|
readonly description: string;
|
||||||
|
/**
|
||||||
|
* Absolute URL to the editing page of the post. Undefined if the post
|
||||||
|
* shouldn't be edited.
|
||||||
|
*/
|
||||||
readonly editUrl?: string;
|
readonly editUrl?: string;
|
||||||
|
/**
|
||||||
|
* Reading time in minutes calculated based on word count.
|
||||||
|
*/
|
||||||
readonly readingTime?: number;
|
readonly readingTime?: number;
|
||||||
readonly truncated?: string;
|
/**
|
||||||
readonly nextItem?: {readonly title: string; readonly permalink: string};
|
* Whether the truncate marker exists in the post's content.
|
||||||
readonly prevItem?: {readonly title: string; readonly permalink: string};
|
*/
|
||||||
|
readonly truncated?: boolean;
|
||||||
|
/**
|
||||||
|
* Used in pagination. Generated after the other metadata, so not readonly.
|
||||||
|
* Content is just a subset of another post's metadata.
|
||||||
|
*/
|
||||||
|
nextItem?: {readonly title: string; readonly permalink: string};
|
||||||
|
/**
|
||||||
|
* Used in pagination. Generated after the other metadata, so not readonly.
|
||||||
|
* Content is just a subset of another post's metadata.
|
||||||
|
*/
|
||||||
|
prevItem?: {readonly title: string; readonly permalink: string};
|
||||||
|
/**
|
||||||
|
* Author metadata, normalized. Should be used in joint with
|
||||||
|
* `assets.authorsImageUrls` on client side.
|
||||||
|
*/
|
||||||
readonly authors: Author[];
|
readonly authors: Author[];
|
||||||
readonly frontMatter: FrontMatter & Record<string, unknown>;
|
/**
|
||||||
|
* Front matter, as-is.
|
||||||
|
*/
|
||||||
|
readonly frontMatter: BlogPostFrontMatter & Record<string, unknown>;
|
||||||
|
/**
|
||||||
|
* Tags, normalized.
|
||||||
|
*/
|
||||||
readonly tags: readonly {
|
readonly tags: readonly {
|
||||||
readonly label: string;
|
readonly label: string;
|
||||||
readonly permalink: string;
|
readonly permalink: string;
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* @returns The edit URL that's directly plugged into metadata.
|
||||||
|
*/
|
||||||
|
export type EditUrlFunction = (editUrlParams: {
|
||||||
|
/**
|
||||||
|
* The root content directory containing this post file, relative to the
|
||||||
|
* site path. Usually the same as `options.path` but can be localized
|
||||||
|
*/
|
||||||
|
blogDirPath: string;
|
||||||
|
/**
|
||||||
|
* Path to this post file, relative to `blogDirPath`
|
||||||
|
*/
|
||||||
|
blogPath: string;
|
||||||
|
/**
|
||||||
|
* @see {@link BlogPostMetadata.permalink}
|
||||||
|
*/
|
||||||
|
permalink: string;
|
||||||
|
/**
|
||||||
|
* Locale name.
|
||||||
|
*/
|
||||||
|
locale: string;
|
||||||
|
}) => string | undefined;
|
||||||
|
|
||||||
|
export type FeedType = 'rss' | 'atom' | 'json';
|
||||||
|
/**
|
||||||
|
* Normalized feed options used within code.
|
||||||
|
*/
|
||||||
|
export type FeedOptions = {
|
||||||
|
/** If `null`, no feed is generated. */
|
||||||
|
type?: FeedType[] | null;
|
||||||
|
/** Title of generated feed. */
|
||||||
|
title?: string;
|
||||||
|
/** Description of generated feed. */
|
||||||
|
description?: string;
|
||||||
|
/** Copyright notice. Required because the feed library marked it that. */
|
||||||
|
copyright: string;
|
||||||
|
/** Language of the feed. */
|
||||||
|
language?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duplicate from ngryman/reading-time to keep stability of API.
|
||||||
|
*/
|
||||||
|
type ReadingTimeOptions = {
|
||||||
|
wordsPerMinute?: number;
|
||||||
|
/**
|
||||||
|
* @param char The character to be matched.
|
||||||
|
* @returns `true` if this character is a word bound.
|
||||||
|
*/
|
||||||
|
wordBound?: (char: string) => boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the default reading time implementation.
|
||||||
|
* @returns The reading time directly plugged into metadata.
|
||||||
|
*/
|
||||||
|
export type ReadingTimeFunction = (params: {
|
||||||
|
/** Markdown content. */
|
||||||
|
content: string;
|
||||||
|
/** Front matter. */
|
||||||
|
frontMatter?: BlogPostFrontMatter & Record<string, unknown>;
|
||||||
|
/** Options accepted by ngryman/reading-time. */
|
||||||
|
options?: ReadingTimeOptions;
|
||||||
|
}) => number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns The reading time directly plugged into metadata. `undefined` to
|
||||||
|
* hide reading time for a specific post.
|
||||||
|
*/
|
||||||
|
export type ReadingTimeFunctionOption = (
|
||||||
|
/**
|
||||||
|
* The `options` is not provided by the caller; the user can inject their
|
||||||
|
* own option values into `defaultReadingTime`
|
||||||
|
*/
|
||||||
|
params: Required<Omit<Parameters<ReadingTimeFunction>[0], 'options'>> & {
|
||||||
|
/**
|
||||||
|
* The default reading time implementation from ngryman/reading-time.
|
||||||
|
*/
|
||||||
|
defaultReadingTime: ReadingTimeFunction;
|
||||||
|
},
|
||||||
|
) => number | undefined;
|
||||||
|
/**
|
||||||
|
* Plugin options after normalization.
|
||||||
|
*/
|
||||||
|
export type PluginOptions = RemarkAndRehypePluginOptions & {
|
||||||
|
/** Plugin ID. */
|
||||||
|
id?: string;
|
||||||
|
/**
|
||||||
|
* Path to the blog content directory on the file system, relative to site
|
||||||
|
* directory.
|
||||||
|
*/
|
||||||
|
path: string;
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
/**
|
||||||
|
* URL route for the tags section of your blog. Will be appended to
|
||||||
|
* `routeBasePath`. **DO NOT** include a trailing slash.
|
||||||
|
*/
|
||||||
|
tagsBasePath: string;
|
||||||
|
/**
|
||||||
|
* 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: string | null;
|
||||||
|
/**
|
||||||
|
* Array of glob patterns matching Markdown files to be built, relative to
|
||||||
|
* the content path.
|
||||||
|
*/
|
||||||
|
include: string[];
|
||||||
|
/**
|
||||||
|
* Array of glob patterns matching Markdown files to be excluded. Serves as
|
||||||
|
* refinement based on the `include` option.
|
||||||
|
*/
|
||||||
|
exclude: string[];
|
||||||
|
/**
|
||||||
|
* Number of posts to show per page in the listing page. Use `'ALL'` to
|
||||||
|
* display all posts on one listing page.
|
||||||
|
*/
|
||||||
|
postsPerPage: number | 'ALL';
|
||||||
|
/** Root component of the blog listing page. */
|
||||||
|
blogListComponent: string;
|
||||||
|
/** Root component of each blog post page. */
|
||||||
|
blogPostComponent: string;
|
||||||
|
/** Root component of the tags list page. */
|
||||||
|
blogTagsListComponent: string;
|
||||||
|
/** Root component of the "posts containing tag" page. */
|
||||||
|
blogTagsPostsComponent: string;
|
||||||
|
/** Root component of the blog archive page. */
|
||||||
|
blogArchiveComponent: string;
|
||||||
|
/** Blog page title for better SEO. */
|
||||||
|
blogTitle: string;
|
||||||
|
/** Blog page meta description for better SEO. */
|
||||||
|
blogDescription: string;
|
||||||
|
/**
|
||||||
|
* Number of blog post elements to show in the blog sidebar. `'ALL'` to show
|
||||||
|
* all blog posts; `0` to disable.
|
||||||
|
*/
|
||||||
|
blogSidebarCount: number | 'ALL';
|
||||||
|
/** Title of the blog sidebar. */
|
||||||
|
blogSidebarTitle: string;
|
||||||
|
/** Truncate marker marking where the summary ends. */
|
||||||
|
truncateMarker: RegExp;
|
||||||
|
/** Show estimated reading time for the blog post. */
|
||||||
|
showReadingTime: boolean;
|
||||||
|
/** Blog feed. */
|
||||||
|
feedOptions: FeedOptions;
|
||||||
|
/**
|
||||||
|
* Base URL to edit your site. The final URL is computed by `editUrl +
|
||||||
|
* relativePostPath`. Using a function allows more nuanced control for each
|
||||||
|
* file. Omitting this variable entirely will disable edit links.
|
||||||
|
*/
|
||||||
|
editUrl?: string | EditUrlFunction;
|
||||||
|
/**
|
||||||
|
* The edit URL will target the localized file, instead of the original
|
||||||
|
* unlocalized file. Ignored when `editUrl` is a function.
|
||||||
|
*/
|
||||||
|
editLocalizedFiles?: boolean;
|
||||||
|
admonitions: Record<string, unknown>;
|
||||||
|
/** Path to the authors map file, relative to the blog content directory. */
|
||||||
|
authorsMapPath: string;
|
||||||
|
/** A callback to customize the reading time number displayed. */
|
||||||
|
readingTime: ReadingTimeFunctionOption;
|
||||||
|
/** Governs the direction of blog post sorting. */
|
||||||
|
sortPosts: 'ascending' | 'descending';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feed options, as provided by user config. `type` accepts `all` as shortcut
|
||||||
|
*/
|
||||||
|
export type UserFeedOptions = Overwrite<
|
||||||
|
Partial<FeedOptions>,
|
||||||
|
{
|
||||||
|
/** Type of feed to be generated. Use `null` to disable generation. */
|
||||||
|
type?: FeedOptions['type'] | 'all' | FeedType;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
/**
|
||||||
|
* Options as provided in the user config (before normalization)
|
||||||
|
*/
|
||||||
|
export type Options = Overwrite<
|
||||||
|
Partial<PluginOptions>,
|
||||||
|
{
|
||||||
|
/** Blog feed. */
|
||||||
|
feedOptions?: UserFeedOptions;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type TagModule = {
|
||||||
|
/** Permalink of the tag's own page. */
|
||||||
|
permalink: string;
|
||||||
|
/** Name of the tag. */
|
||||||
|
name: string;
|
||||||
|
/** Number of posts with this tag. */
|
||||||
|
count: number;
|
||||||
|
/** The tags list page. */
|
||||||
|
allTagsPath: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BlogSidebar = {
|
||||||
|
title: string;
|
||||||
|
items: {title: string; permalink: string}[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@theme/BlogPostPage' {
|
||||||
|
import type {TOCItem} from '@docusaurus/types';
|
||||||
|
import type {
|
||||||
|
BlogPostFrontMatter,
|
||||||
|
BlogPostMetadata,
|
||||||
|
Assets,
|
||||||
|
BlogSidebar,
|
||||||
|
} from '@docusaurus/plugin-content-blog';
|
||||||
|
import type {Overwrite} from 'utility-types';
|
||||||
|
|
||||||
|
export type FrontMatter = BlogPostFrontMatter;
|
||||||
|
|
||||||
|
export type Metadata = Overwrite<
|
||||||
|
BlogPostMetadata,
|
||||||
|
{
|
||||||
|
/** The publish date of the post. Serialized from the `Date` object. */
|
||||||
|
date: string;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
|
||||||
export type Content = {
|
export type Content = {
|
||||||
|
// TODO remove this. `metadata.frontMatter` is preferred because it can be
|
||||||
|
// accessed in enhanced plugins
|
||||||
|
/** Same as `metadata.frontMatter` */
|
||||||
readonly frontMatter: FrontMatter;
|
readonly frontMatter: FrontMatter;
|
||||||
|
/**
|
||||||
|
* Usually image assets that may be collocated like `./img/thumbnail.png`.
|
||||||
|
* The loader would also bundle these assets and the client should use these
|
||||||
|
* in priority.
|
||||||
|
*/
|
||||||
readonly assets: Assets;
|
readonly assets: Assets;
|
||||||
|
/** Metadata of the post. */
|
||||||
readonly metadata: Metadata;
|
readonly metadata: Metadata;
|
||||||
|
/** A list of TOC items (headings). */
|
||||||
readonly toc: readonly TOCItem[];
|
readonly toc: readonly TOCItem[];
|
||||||
|
/** Renders the actual MDX content. */
|
||||||
(): JSX.Element;
|
(): JSX.Element;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
/** Blog sidebar. */
|
||||||
readonly sidebar: BlogSidebar;
|
readonly sidebar: BlogSidebar;
|
||||||
|
/** Content of this post as an MDX component, with useful metadata. */
|
||||||
readonly content: Content;
|
readonly content: Content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,23 +500,38 @@ declare module '@theme/BlogPostPage' {
|
||||||
|
|
||||||
declare module '@theme/BlogListPage' {
|
declare module '@theme/BlogListPage' {
|
||||||
import type {Content} from '@theme/BlogPostPage';
|
import type {Content} from '@theme/BlogPostPage';
|
||||||
import type {BlogSidebar} from '@theme/BlogSidebar';
|
import type {BlogSidebar} from '@docusaurus/plugin-content-blog';
|
||||||
|
|
||||||
export type Metadata = {
|
export type Metadata = {
|
||||||
|
/** Title of the entire blog. */
|
||||||
readonly blogTitle: string;
|
readonly blogTitle: string;
|
||||||
|
/** Blog description. */
|
||||||
readonly blogDescription: string;
|
readonly blogDescription: string;
|
||||||
|
/** Permalink to the next list page. */
|
||||||
readonly nextPage?: string;
|
readonly nextPage?: string;
|
||||||
readonly page: number;
|
/** Permalink of the current page. */
|
||||||
readonly permalink: string;
|
readonly permalink: string;
|
||||||
readonly postsPerPage: number;
|
/** Permalink to the previous list page. */
|
||||||
readonly previousPage?: string;
|
readonly previousPage?: string;
|
||||||
|
/** Index of the current page, 1-based. */
|
||||||
|
readonly page: number;
|
||||||
|
/** Posts displayed on each list page. */
|
||||||
|
readonly postsPerPage: number;
|
||||||
|
/** Total number of posts in the entire blog. */
|
||||||
readonly totalCount: number;
|
readonly totalCount: number;
|
||||||
|
/** Total number of list pages. */
|
||||||
readonly totalPages: number;
|
readonly totalPages: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
/** Blog sidebar. */
|
||||||
readonly sidebar: BlogSidebar;
|
readonly sidebar: BlogSidebar;
|
||||||
|
/** Metadata of the current listing page. */
|
||||||
readonly metadata: Metadata;
|
readonly metadata: Metadata;
|
||||||
|
/**
|
||||||
|
* Array of blog posts included on this page. Every post's metadata is also
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
readonly items: readonly {readonly content: Content}[];
|
readonly items: readonly {readonly content: Content}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,34 +539,34 @@ declare module '@theme/BlogListPage' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/BlogTagsListPage' {
|
declare module '@theme/BlogTagsListPage' {
|
||||||
import type {BlogSidebar} from '@theme/BlogSidebar';
|
import type {BlogSidebar, TagModule} from '@docusaurus/plugin-content-blog';
|
||||||
|
|
||||||
export type Tag = {
|
|
||||||
permalink: string;
|
|
||||||
name: string;
|
|
||||||
count: number;
|
|
||||||
allTagsPath: string;
|
|
||||||
slug: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
/** Blog sidebar. */
|
||||||
readonly sidebar: BlogSidebar;
|
readonly sidebar: BlogSidebar;
|
||||||
readonly tags: Readonly<Record<string, Tag>>;
|
/** A map from tag names to the full tag module. */
|
||||||
|
readonly tags: Readonly<Record<string, TagModule>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function BlogTagsListPage(props: Props): JSX.Element;
|
export default function BlogTagsListPage(props: Props): JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/BlogTagsPostsPage' {
|
declare module '@theme/BlogTagsPostsPage' {
|
||||||
import type {BlogSidebar} from '@theme/BlogSidebar';
|
import type {BlogSidebar, TagModule} from '@docusaurus/plugin-content-blog';
|
||||||
import type {Tag} from '@theme/BlogTagsListPage';
|
|
||||||
import type {Content} from '@theme/BlogPostPage';
|
import type {Content} from '@theme/BlogPostPage';
|
||||||
import type {Metadata} from '@theme/BlogListPage';
|
import type {Metadata} from '@theme/BlogListPage';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
/** Blog sidebar. */
|
||||||
readonly sidebar: BlogSidebar;
|
readonly sidebar: BlogSidebar;
|
||||||
readonly metadata: Tag;
|
/** Metadata of this tag. */
|
||||||
|
readonly metadata: TagModule;
|
||||||
|
/** Looks exactly the same as the posts list page */
|
||||||
readonly listMetadata: Metadata;
|
readonly listMetadata: Metadata;
|
||||||
|
/**
|
||||||
|
* Array of blog posts included on this page. Every post's metadata is also
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
readonly items: readonly {readonly content: Content}[];
|
readonly items: readonly {readonly content: Content}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,10 +576,13 @@ declare module '@theme/BlogTagsPostsPage' {
|
||||||
declare module '@theme/BlogArchivePage' {
|
declare module '@theme/BlogArchivePage' {
|
||||||
import type {Content} from '@theme/BlogPostPage';
|
import type {Content} from '@theme/BlogPostPage';
|
||||||
|
|
||||||
|
/** We may add extra metadata or prune some metadata from here */
|
||||||
export type ArchiveBlogPost = Content;
|
export type ArchiveBlogPost = Content;
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
/** The entirety of the blog's data. */
|
||||||
readonly archive: {
|
readonly archive: {
|
||||||
|
/** All posts. Can select any useful data/metadata to render. */
|
||||||
readonly blogPosts: readonly ArchiveBlogPost[];
|
readonly blogPosts: readonly ArchiveBlogPost[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,12 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {Tag} from '@docusaurus/utils';
|
|
||||||
import type {
|
import type {
|
||||||
BrokenMarkdownLink,
|
BrokenMarkdownLink,
|
||||||
ContentPaths,
|
ContentPaths,
|
||||||
} from '@docusaurus/utils/lib/markdownLinks';
|
} from '@docusaurus/utils/lib/markdownLinks';
|
||||||
import type {
|
import type {BlogPostMetadata} from '@docusaurus/plugin-content-blog';
|
||||||
BlogPostFrontMatter,
|
import type {Metadata as BlogPaginatedMetadata} from '@theme/BlogListPage';
|
||||||
Author,
|
|
||||||
} from '@docusaurus/plugin-content-blog';
|
|
||||||
|
|
||||||
export type BlogContentPaths = ContentPaths;
|
export type BlogContentPaths = ContentPaths;
|
||||||
|
|
||||||
|
@ -42,65 +39,15 @@ export interface BlogTag {
|
||||||
|
|
||||||
export interface BlogPost {
|
export interface BlogPost {
|
||||||
id: string;
|
id: string;
|
||||||
metadata: MetaData;
|
metadata: BlogPostMetadata;
|
||||||
content: string;
|
content: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BlogPaginatedMetadata {
|
|
||||||
permalink: string;
|
|
||||||
page: number;
|
|
||||||
postsPerPage: number;
|
|
||||||
totalPages: number;
|
|
||||||
totalCount: number;
|
|
||||||
previousPage: string | null;
|
|
||||||
nextPage: string | null;
|
|
||||||
blogTitle: string;
|
|
||||||
blogDescription: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BlogPaginated {
|
export interface BlogPaginated {
|
||||||
metadata: BlogPaginatedMetadata;
|
metadata: BlogPaginatedMetadata;
|
||||||
items: string[]; // blog post permalinks
|
items: string[]; // blog post permalinks
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetaData {
|
|
||||||
permalink: string;
|
|
||||||
source: string;
|
|
||||||
description: string;
|
|
||||||
date: Date;
|
|
||||||
formattedDate: string;
|
|
||||||
tags: Tag[];
|
|
||||||
title: string;
|
|
||||||
readingTime?: number;
|
|
||||||
prevItem?: Paginator;
|
|
||||||
nextItem?: Paginator;
|
|
||||||
truncated: boolean;
|
|
||||||
editUrl?: string;
|
|
||||||
authors: Author[];
|
|
||||||
frontMatter: BlogPostFrontMatter & Record<string, unknown>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Paginator {
|
|
||||||
title: string;
|
|
||||||
permalink: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BlogItemsToMetadata {
|
|
||||||
[key: string]: MetaData;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TagsModule {
|
|
||||||
[key: string]: TagModule;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TagModule {
|
|
||||||
allTagsPath: string;
|
|
||||||
slug: string;
|
|
||||||
name: string;
|
|
||||||
count: number;
|
|
||||||
permalink: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type BlogBrokenMarkdownLink = BrokenMarkdownLink<BlogContentPaths>;
|
export type BlogBrokenMarkdownLink = BrokenMarkdownLink<BlogContentPaths>;
|
||||||
export type BlogMarkdownLoaderOptions = {
|
export type BlogMarkdownLoaderOptions = {
|
||||||
siteDir: string;
|
siteDir: string;
|
||||||
|
|
|
@ -41,11 +41,7 @@ declare module '@theme/BlogListPaginator' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/BlogSidebar' {
|
declare module '@theme/BlogSidebar' {
|
||||||
export type BlogSidebarItem = {title: string; permalink: string};
|
import type {BlogSidebar} from '@docusaurus/plugin-content-blog';
|
||||||
export type BlogSidebar = {
|
|
||||||
title: string;
|
|
||||||
items: BlogSidebarItem[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly sidebar: BlogSidebar;
|
readonly sidebar: BlogSidebar;
|
||||||
|
@ -106,7 +102,7 @@ declare module '@theme/BlogPostPaginator' {
|
||||||
declare module '@theme/BlogLayout' {
|
declare module '@theme/BlogLayout' {
|
||||||
import type {ReactNode} from 'react';
|
import type {ReactNode} from 'react';
|
||||||
import type {Props as LayoutProps} from '@theme/Layout';
|
import type {Props as LayoutProps} from '@theme/Layout';
|
||||||
import type {BlogSidebar} from '@theme/BlogSidebar';
|
import type {BlogSidebar} from '@docusaurus/plugin-content-blog';
|
||||||
|
|
||||||
export interface Props extends LayoutProps {
|
export interface Props extends LayoutProps {
|
||||||
readonly sidebar?: BlogSidebar;
|
readonly sidebar?: BlogSidebar;
|
||||||
|
|
|
@ -22,7 +22,7 @@ export default function BlogLayout(props: Props): JSX.Element {
|
||||||
<div className="row">
|
<div className="row">
|
||||||
{hasSidebar && (
|
{hasSidebar && (
|
||||||
<aside className="col col--3">
|
<aside className="col col--3">
|
||||||
<BlogSidebar sidebar={sidebar!} />
|
<BlogSidebar sidebar={sidebar} />
|
||||||
</aside>
|
</aside>
|
||||||
)}
|
)}
|
||||||
<main
|
<main
|
||||||
|
|
|
@ -70,8 +70,8 @@ export type TaggedItemGroup<Item> = {
|
||||||
* override the other
|
* override the other
|
||||||
*/
|
*/
|
||||||
export function groupTaggedItems<Item>(
|
export function groupTaggedItems<Item>(
|
||||||
items: Item[],
|
items: readonly Item[],
|
||||||
getItemTags: (item: Item) => Tag[],
|
getItemTags: (item: Item) => readonly Tag[],
|
||||||
): Record<string, TaggedItemGroup<Item>> {
|
): Record<string, TaggedItemGroup<Item>> {
|
||||||
const result: Record<string, TaggedItemGroup<Item>> = {};
|
const result: Record<string, TaggedItemGroup<Item>> = {};
|
||||||
|
|
||||||
|
|
|
@ -37,32 +37,32 @@ Accepted fields:
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `path` | `string` | `'blog'` | Path to the blog content directory on the filesystem, relative to site dir. |
|
| `path` | `string` | `'blog'` | Path to the blog content directory on the file system, relative to site dir. |
|
||||||
| `editUrl` | <code>string \| EditUrlFunction</code> | `undefined` | Base URL to edit your site. The final URL is computed by `editUrl + relativeDocPath`. Using a function allows more nuanced control for each file. Omitting this variable entirely will disable edit links. |
|
| `editUrl` | <code>string \| EditUrlFunction</code> | `undefined` | Base URL to edit your site. The final URL is computed by `editUrl + relativePostPath`. Using a function allows more nuanced control for each file. Omitting this variable entirely will disable edit links. |
|
||||||
| `editLocalizedFiles` | `boolean` | `false` | The edit URL will target the localized file, instead of the original unlocalized file. Ignored when `editUrl` is a function. |
|
| `editLocalizedFiles` | `boolean` | `false` | The edit URL will target the localized file, instead of the original unlocalized file. Ignored when `editUrl` is a function. |
|
||||||
| `blogTitle` | `string` | `'Blog'` | Blog page title for better SEO. |
|
| `blogTitle` | `string` | `'Blog'` | Blog page title for better SEO. |
|
||||||
| `blogDescription` | `string` | `'Blog'` | Blog page meta description for better SEO. |
|
| `blogDescription` | `string` | `'Blog'` | Blog page meta description for better SEO. |
|
||||||
| `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 list page of your site. It is prepended to the `routeBasePath`. |
|
| `tagsBasePath` | `string` | `'tags'` | URL route for the tags section of your blog. Will be appended to `routeBasePath`. **DO NOT** include a trailing slash. |
|
||||||
| `archiveBasePath` | <code>string \| null</code> | `'/archive'` | URL route for the archive blog section of your site. It is prepended to the `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}']` | Matching files will be included and processed. |
|
| `include` | `string[]` | `['**/*.{md,mdx}']` | Array of glob patterns matching Markdown files to be built, relative to the content path. |
|
||||||
| `exclude` | `string[]` | _See example configuration_ | No route will be created for matching files. |
|
| `exclude` | `string[]` | _See example configuration_ | Array of glob patterns matching Markdown files to be excluded. Serves as refinement based on the `include` option. |
|
||||||
| `postsPerPage` | <code>number \| 'ALL'</code> | `10` | Number of posts to show per page in the listing page. Use `'ALL'` to display all posts on one listing page. |
|
| `postsPerPage` | <code>number \| 'ALL'</code> | `10` | Number of posts to show per page in the listing page. Use `'ALL'` to display all posts on one listing page. |
|
||||||
| `blogListComponent` | `string` | `'@theme/BlogListPage'` | Root component of the blog listing page. |
|
| `blogListComponent` | `string` | `'@theme/BlogListPage'` | Root component of the blog listing page. |
|
||||||
| `blogPostComponent` | `string` | `'@theme/BlogPostPage'` | Root component of each blog post page. |
|
| `blogPostComponent` | `string` | `'@theme/BlogPostPage'` | Root component of each blog post page. |
|
||||||
| `blogTagsListComponent` | `string` | `'@theme/BlogTagsListPage'` | Root component of the tags list page |
|
| `blogTagsListComponent` | `string` | `'@theme/BlogTagsListPage'` | Root component of the tags list page. |
|
||||||
| `blogTagsPostsComponent` | `string` | `'@theme/BlogTagsPostsPage'` | Root component of the "posts containing tag" page. |
|
| `blogTagsPostsComponent` | `string` | `'@theme/BlogTagsPostsPage'` | Root component of the "posts containing tag" page. |
|
||||||
| `blogArchiveComponent` | `string` | `'@theme/BlogArchivePage'` | Root component of the blog archive page. |
|
| `blogArchiveComponent` | `string` | `'@theme/BlogArchivePage'` | Root component of the blog archive page. |
|
||||||
| `remarkPlugins` | `any[]` | `[]` | Remark plugins passed to MDX. |
|
| `remarkPlugins` | `any[]` | `[]` | Remark plugins passed to MDX. |
|
||||||
| `rehypePlugins` | `any[]` | `[]` | Rehype plugins passed to MDX. |
|
| `rehypePlugins` | `any[]` | `[]` | Rehype plugins passed to MDX. |
|
||||||
| `beforeDefaultRemarkPlugins` | `any[]` | `[]` | Custom Remark plugins passed to MDX before the default Docusaurus Remark plugins. |
|
| `beforeDefaultRemarkPlugins` | `any[]` | `[]` | Custom Remark plugins passed to MDX before the default Docusaurus Remark plugins. |
|
||||||
| `beforeDefaultRehypePlugins` | `any[]` | `[]` | Custom Rehype plugins passed to MDX before the default Docusaurus Rehype plugins. |
|
| `beforeDefaultRehypePlugins` | `any[]` | `[]` | Custom Rehype plugins passed to MDX before the default Docusaurus Rehype plugins. |
|
||||||
| `truncateMarker` | `string` | `/<!--\s*(truncate)\s*-->/` | Truncate marker, can be a regex or string. |
|
| `truncateMarker` | `RegExp` | `/<!--\s*(truncate)\s*-->/` | Truncate marker marking where the summary ends. |
|
||||||
| `showReadingTime` | `boolean` | `true` | Show estimated reading time for the blog post. |
|
| `showReadingTime` | `boolean` | `true` | Show estimated reading time for the blog post. |
|
||||||
| `readingTime` | `ReadingTimeFunctionOption` | The default reading time | A callback to customize the reading time number displayed. |
|
| `readingTime` | `ReadingTimeFunctionOption` | The default reading time | A callback to customize the reading time number displayed. |
|
||||||
| `authorsMapPath` | `string` | `'authors.yml'` | Path to the authors map file, relative to the blog content directory specified with `path`. Can also be a `json` file. |
|
| `authorsMapPath` | `string` | `'authors.yml'` | Path to the authors map file, relative to the blog content directory. |
|
||||||
| `feedOptions` | _See below_ | `{type: ['rss', 'atom']}` | Blog feed. |
|
| `feedOptions` | _See below_ | `{type: ['rss', 'atom']}` | Blog feed. |
|
||||||
| `feedOptions.type` | <code>FeedType \| FeedType[] \| 'all' \| null</code> | **Required** | Type of feed to be generated. Use `null` to disable generation. |
|
| `feedOptions.type` | <code>FeedType \| FeedType[] \| 'all' \| null</code> | **Required** | Type of feed to be generated. Use `null` to disable generation. |
|
||||||
| `feedOptions.title` | `string` | `siteConfig.title` | Title of the feed. |
|
| `feedOptions.title` | `string` | `siteConfig.title` | Title of the feed. |
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue