mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 07:37:19 +02:00
feat(content-blog): new readingTime plugin option (#5702)
This commit is contained in:
parent
92002b6bd3
commit
9ad6de2b85
8 changed files with 179 additions and 1 deletions
|
@ -77,6 +77,8 @@ describe('blogFeed', () => {
|
|||
type: [feedType],
|
||||
copyright: 'Copyright',
|
||||
},
|
||||
readingTime: ({content, defaultReadingTime}) =>
|
||||
defaultReadingTime({content}),
|
||||
} as PluginOptions,
|
||||
);
|
||||
|
||||
|
@ -111,6 +113,8 @@ describe('blogFeed', () => {
|
|||
type: [feedType],
|
||||
copyright: 'Copyright',
|
||||
},
|
||||
readingTime: ({content, defaultReadingTime}) =>
|
||||
defaultReadingTime({content}),
|
||||
} as PluginOptions,
|
||||
);
|
||||
const feedContent =
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
BlogContentPaths,
|
||||
BlogMarkdownLoaderOptions,
|
||||
BlogTags,
|
||||
ReadingTimeFunction,
|
||||
} from './types';
|
||||
import {
|
||||
parseMarkdownFile,
|
||||
|
@ -111,6 +112,10 @@ async function parseBlogPostMarkdownFile(blogSourceAbsolute: string) {
|
|||
};
|
||||
}
|
||||
|
||||
const defaultReadingTime: ReadingTimeFunction = ({content, options}) => {
|
||||
return readingTime(content, options).minutes;
|
||||
};
|
||||
|
||||
async function processBlogSourceFile(
|
||||
blogSourceRelative: string,
|
||||
contentPaths: BlogContentPaths,
|
||||
|
@ -227,7 +232,13 @@ async function processBlogSourceFile(
|
|||
date,
|
||||
formattedDate,
|
||||
tags: normalizeFrontMatterTags(tagsBasePath, frontMatter.tags),
|
||||
readingTime: showReadingTime ? readingTime(content).minutes : undefined,
|
||||
readingTime: showReadingTime
|
||||
? options.readingTime({
|
||||
content,
|
||||
frontMatter,
|
||||
defaultReadingTime,
|
||||
})
|
||||
: undefined,
|
||||
truncated: truncateMarker?.test(content) || false,
|
||||
authors,
|
||||
},
|
||||
|
|
|
@ -41,6 +41,7 @@ export const DEFAULT_OPTIONS: PluginOptions = {
|
|||
path: 'blog',
|
||||
editLocalizedFiles: false,
|
||||
authorsMapPath: 'authors.yml',
|
||||
readingTime: ({content, defaultReadingTime}) => defaultReadingTime({content}),
|
||||
};
|
||||
|
||||
export const PluginOptionSchema = Joi.object<PluginOptions>({
|
||||
|
@ -113,4 +114,5 @@ export const PluginOptionSchema = Joi.object<PluginOptions>({
|
|||
language: Joi.string(),
|
||||
}).default(DEFAULT_OPTIONS.feedOptions),
|
||||
authorsMapPath: Joi.string().default(DEFAULT_OPTIONS.authorsMapPath),
|
||||
readingTime: Joi.function().default(() => DEFAULT_OPTIONS.readingTime),
|
||||
});
|
||||
|
|
|
@ -12,6 +12,7 @@ import type {
|
|||
ContentPaths,
|
||||
} from '@docusaurus/utils/lib/markdownLinks';
|
||||
import {Overwrite} from 'utility-types';
|
||||
import {BlogPostFrontMatter} from './blogFrontMatter';
|
||||
|
||||
export type BlogContentPaths = ContentPaths;
|
||||
|
||||
|
@ -46,6 +47,24 @@ export type EditUrlFunction = (editUrlParams: {
|
|||
locale: string;
|
||||
}) => string | undefined;
|
||||
|
||||
// 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;
|
||||
|
@ -76,6 +95,7 @@ export type PluginOptions = RemarkAndRehypePluginOptions & {
|
|||
editLocalizedFiles?: boolean;
|
||||
admonitions: Record<string, unknown>;
|
||||
authorsMapPath: string;
|
||||
readingTime: ReadingTimeFunctionOption;
|
||||
};
|
||||
|
||||
// Options, as provided in the user config (before normalization)
|
||||
|
|
|
@ -3,6 +3,7 @@ title: Blog post MDX Feed tests
|
|||
authors:
|
||||
- slorber
|
||||
tags: [blog, docusaurus, long-long, long-long-long, long-long-long-long]
|
||||
hide_reading_time: true
|
||||
---
|
||||
|
||||
Some MDX tests, mostly to test how the RSS feed render those
|
||||
|
|
|
@ -31,6 +31,10 @@ const dogfoodingPluginInstances = [
|
|||
title: 'Docusaurus Tests Blog',
|
||||
copyright: `Copyright © ${new Date().getFullYear()} Facebook, Inc.`,
|
||||
},
|
||||
readingTime: ({content, frontMatter, defaultReadingTime}) =>
|
||||
frontMatter.hide_reading_time
|
||||
? undefined
|
||||
: defaultReadingTime({content, options: {wordsPerMinute: 5}}),
|
||||
}),
|
||||
],
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ Accepted fields:
|
|||
| `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. |
|
||||
| `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. |
|
||||
| `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. |
|
||||
| `feedOptions` | _See below_ | `{type: ['rss', 'atom']}` | Blog feed. If undefined, no rss feed will be generated. |
|
||||
| `feedOptions.type` | <code>'rss' \| 'atom' \| 'all'</code> (or array of multiple options) | **Required** | Type of feed to be generated. |
|
||||
|
@ -68,6 +69,23 @@ type EditUrlFunction = (params: {
|
|||
permalink: string;
|
||||
locale: string;
|
||||
}) => string | undefined;
|
||||
|
||||
type ReadingTimeOptions = {
|
||||
wordsPerMinute: number;
|
||||
wordBound: (char: string) => boolean;
|
||||
};
|
||||
|
||||
type ReadingTimeFunction = (params: {
|
||||
content: string;
|
||||
frontMatter?: BlogPostFrontMatter & Record<string, unknown>;
|
||||
options?: ReadingTimeOptions;
|
||||
}) => number;
|
||||
|
||||
type ReadingTimeFunctionOption = (params: {
|
||||
content: string;
|
||||
frontMatter: BlogPostFrontMatter & Record<string, unknown>;
|
||||
defaultReadingTime: ReadingTimeFunction;
|
||||
}) => number | undefined;
|
||||
```
|
||||
|
||||
## Example configuration {#ex-config}
|
||||
|
|
|
@ -335,6 +335,124 @@ website/i18n/<locale>/docusaurus-plugin-content-blog/authors.yml
|
|||
|
||||
:::
|
||||
|
||||
## Reading time {#reading-time}
|
||||
|
||||
Docusaurus generates a reading time estimation for each blog post based on word count. We provide an option to customize this.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
blog: {
|
||||
// highlight-start
|
||||
showReadingTime: true, // When set to false, the "x min read" won't be shown
|
||||
readingTime: ({content, frontMatter, defaultReadingTime}) =>
|
||||
defaultReadingTime({content, options: {wordsPerMinute: 300}}),
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
The `readingTime` callback receives three parameters: the blog content text as a string, front matter as a record of string keys and their values, and the default reading time function. It returns a number (reading time in minutes) or `undefined` (disable reading time for this page).
|
||||
|
||||
The default reading time is able to accept additional options: `wordsPerMinute` as a number (default: 300), and `wordBound` as a function from string to boolean. If the string passed to `wordBound` should be a word bound (spaces, tabs, and line breaks by default), the function should return `true`.
|
||||
|
||||
:::tip
|
||||
|
||||
Use the callback for all your customization needs:
|
||||
|
||||
````mdx-code-block
|
||||
<Tabs>
|
||||
<TabItem value="disable-per-post" label="Per-post disabling">
|
||||
|
||||
**Disable reading time on one page:**
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
blog: {
|
||||
showReadingTime: true,
|
||||
// highlight-start
|
||||
readingTime: ({content, frontMatter, defaultReadingTime}) =>
|
||||
frontMatter.hide_reading_time ? undefined : defaultReadingTime({content}),
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
Usage:
|
||||
|
||||
```yml "my-blog-post.md"
|
||||
---
|
||||
hide_reading_time: true
|
||||
---
|
||||
|
||||
This page will no longer display the reading time stats!
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="passing-options" label="Passing options">
|
||||
|
||||
**Pass options to the default reading time function:**
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
blog: {
|
||||
// highlight-start
|
||||
readingTime: ({content, defaultReadingTime}) =>
|
||||
defaultReadingTime({content, options: {wordsPerMinute: 100}}),
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="using-custom-algo" label="Using custom algorithms">
|
||||
|
||||
**Use a custom implementation of reading time:**
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
const myReadingTime = require('./myReadingTime');
|
||||
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
blog: {
|
||||
// highlight-next-line
|
||||
readingTime: ({content}) => myReadingTime(content),
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
````
|
||||
|
||||
:::
|
||||
|
||||
## Feed {#feed}
|
||||
|
||||
You can generate RSS/Atom feed by passing feedOptions. By default, RSS and Atom feeds are generated. To disable feed generation, set `feedOptions.type` to `null`.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue