@docusaurus/plugin-content-blog 2.0.0-beta.677e53d4d → 2.0.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/.tsbuildinfo +1 -1
- package/lib/authors.d.ts +23 -0
- package/lib/authors.js +150 -0
- package/lib/blogFrontMatter.d.ts +19 -6
- package/lib/blogFrontMatter.js +31 -19
- package/lib/blogUtils.d.ts +10 -2
- package/lib/blogUtils.js +146 -104
- package/lib/index.js +78 -77
- package/lib/markdownLoader.js +3 -3
- package/lib/pluginOptionSchema.d.ts +3 -26
- package/lib/pluginOptionSchema.js +22 -7
- package/lib/translations.d.ts +10 -0
- package/lib/translations.js +53 -0
- package/lib/types.d.ts +38 -14
- package/package.json +13 -11
- package/src/__tests__/__fixtures__/authorsMapFiles/authors.json +29 -0
- package/src/__tests__/__fixtures__/authorsMapFiles/authors.yml +27 -0
- package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad1.json +5 -0
- package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad1.yml +3 -0
- package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad2.json +3 -0
- package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad2.yml +2 -0
- package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad3.json +8 -0
- package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad3.yml +3 -0
- package/src/__tests__/__fixtures__/component/Typography.tsx +6 -0
- package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathEmpty/empty +0 -0
- package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathJson1/authors.json +0 -0
- package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathJson2/authors.json +0 -0
- package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathNestedYml/sub/folder/authors.yml +0 -0
- package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathYml1/authors.yml +0 -0
- package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathYml2/authors.yml +0 -0
- package/src/__tests__/__fixtures__/website/blog/2018-12-14-Happy-First-Birthday-Slash.md +3 -0
- package/src/__tests__/__fixtures__/website/blog/_partials/somePartial.md +3 -0
- package/src/__tests__/__fixtures__/website/blog/_partials/subfolder/somePartial.md +3 -0
- package/src/__tests__/__fixtures__/website/blog/_somePartial.md +3 -0
- package/src/__tests__/__fixtures__/website/blog/authors.yml +4 -0
- package/src/__tests__/__fixtures__/website/blog/mdx-blog-post.mdx +36 -0
- package/src/__tests__/__fixtures__/website/blog/simple-slug.md +4 -0
- package/src/__tests__/__fixtures__/website/i18n/en/docusaurus-plugin-content-blog/2018-12-14-Happy-First-Birthday-Slash.md +3 -0
- package/src/__tests__/__fixtures__/website/i18n/en/docusaurus-plugin-content-blog/authors.yml +5 -0
- package/src/__tests__/__snapshots__/generateBlogFeed.test.ts.snap +81 -3
- package/src/__tests__/__snapshots__/translations.test.ts.snap +64 -0
- package/src/__tests__/authors.test.ts +608 -0
- package/src/__tests__/blogFrontMatter.test.ts +93 -16
- package/src/__tests__/blogUtils.test.ts +94 -0
- package/src/__tests__/generateBlogFeed.test.ts +7 -1
- package/src/__tests__/index.test.ts +63 -12
- package/src/__tests__/pluginOptionSchema.test.ts +3 -3
- package/src/__tests__/translations.test.ts +92 -0
- package/src/authors.ts +202 -0
- package/src/blogFrontMatter.ts +73 -33
- package/src/blogUtils.ts +206 -131
- package/src/index.ts +98 -71
- package/{index.d.ts → src/plugin-content-blog.d.ts} +35 -31
- package/src/pluginOptionSchema.ts +25 -9
- package/src/translations.ts +63 -0
- package/src/types.ts +48 -16
package/src/index.ts
CHANGED
|
@@ -16,12 +16,14 @@ import {
|
|
|
16
16
|
reportMessage,
|
|
17
17
|
posixPath,
|
|
18
18
|
addTrailingPathSeparator,
|
|
19
|
+
createAbsoluteFilePathMatcher,
|
|
19
20
|
} from '@docusaurus/utils';
|
|
20
21
|
import {
|
|
21
22
|
STATIC_DIR_NAME,
|
|
22
23
|
DEFAULT_PLUGIN_ID,
|
|
23
24
|
} from '@docusaurus/core/lib/constants';
|
|
24
|
-
import {
|
|
25
|
+
import {translateContent, getTranslationFiles} from './translations';
|
|
26
|
+
import {flatten, take} from 'lodash';
|
|
25
27
|
|
|
26
28
|
import {
|
|
27
29
|
PluginOptions,
|
|
@@ -30,9 +32,10 @@ import {
|
|
|
30
32
|
BlogItemsToMetadata,
|
|
31
33
|
TagsModule,
|
|
32
34
|
BlogPaginated,
|
|
33
|
-
BlogPost,
|
|
34
35
|
BlogContentPaths,
|
|
35
36
|
BlogMarkdownLoaderOptions,
|
|
37
|
+
MetaData,
|
|
38
|
+
Assets,
|
|
36
39
|
} from './types';
|
|
37
40
|
import {PluginOptionSchema} from './pluginOptionSchema';
|
|
38
41
|
import {
|
|
@@ -50,7 +53,9 @@ import {
|
|
|
50
53
|
generateBlogPosts,
|
|
51
54
|
getContentPathList,
|
|
52
55
|
getSourceToPermalink,
|
|
56
|
+
getBlogTags,
|
|
53
57
|
} from './blogUtils';
|
|
58
|
+
import {BlogPostFrontMatter} from './blogFrontMatter';
|
|
54
59
|
|
|
55
60
|
export default function pluginContentBlog(
|
|
56
61
|
context: LoadContext,
|
|
@@ -64,7 +69,7 @@ export default function pluginContentBlog(
|
|
|
64
69
|
|
|
65
70
|
const {
|
|
66
71
|
siteDir,
|
|
67
|
-
siteConfig: {onBrokenMarkdownLinks},
|
|
72
|
+
siteConfig: {onBrokenMarkdownLinks, baseUrl},
|
|
68
73
|
generatedFilesDir,
|
|
69
74
|
i18n: {currentLocale},
|
|
70
75
|
} = context;
|
|
@@ -92,36 +97,44 @@ export default function pluginContentBlog(
|
|
|
92
97
|
name: 'docusaurus-plugin-content-blog',
|
|
93
98
|
|
|
94
99
|
getPathsToWatch() {
|
|
95
|
-
const {include
|
|
96
|
-
|
|
100
|
+
const {include, authorsMapPath} = options;
|
|
101
|
+
const contentMarkdownGlobs = flatten(
|
|
97
102
|
getContentPathList(contentPaths).map((contentPath) => {
|
|
98
103
|
return include.map((pattern) => `${contentPath}/${pattern}`);
|
|
99
104
|
}),
|
|
100
105
|
);
|
|
101
|
-
},
|
|
102
106
|
|
|
103
|
-
|
|
104
|
-
const
|
|
107
|
+
// TODO: we should read this path in plugin! but plugins do not support async init for now :'(
|
|
108
|
+
// const authorsMapFilePath = await getAuthorsMapFilePath({authorsMapPath,contentPaths,});
|
|
109
|
+
// simplified impl, better than nothing for now:
|
|
110
|
+
const authorsMapFilePath = path.join(
|
|
111
|
+
contentPaths.contentPath,
|
|
112
|
+
authorsMapPath,
|
|
113
|
+
);
|
|
105
114
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
115
|
+
return [authorsMapFilePath, ...contentMarkdownGlobs];
|
|
116
|
+
},
|
|
109
117
|
|
|
110
|
-
|
|
118
|
+
async getTranslationFiles() {
|
|
119
|
+
return getTranslationFiles(options);
|
|
111
120
|
},
|
|
112
121
|
|
|
113
122
|
// Fetches blog contents and returns metadata for the necessary routes.
|
|
114
123
|
async loadContent() {
|
|
115
|
-
const {
|
|
124
|
+
const {
|
|
125
|
+
postsPerPage: postsPerPageOption,
|
|
126
|
+
routeBasePath,
|
|
127
|
+
tagsBasePath,
|
|
128
|
+
blogDescription,
|
|
129
|
+
blogTitle,
|
|
130
|
+
blogSidebarTitle,
|
|
131
|
+
} = options;
|
|
116
132
|
|
|
117
|
-
const blogPosts
|
|
118
|
-
contentPaths,
|
|
119
|
-
context,
|
|
120
|
-
options,
|
|
121
|
-
);
|
|
133
|
+
const blogPosts = await generateBlogPosts(contentPaths, context, options);
|
|
122
134
|
|
|
123
135
|
if (!blogPosts.length) {
|
|
124
136
|
return {
|
|
137
|
+
blogSidebarTitle,
|
|
125
138
|
blogPosts: [],
|
|
126
139
|
blogListPaginated: [],
|
|
127
140
|
blogTags: {},
|
|
@@ -152,18 +165,17 @@ export default function pluginContentBlog(
|
|
|
152
165
|
// Blog pagination routes.
|
|
153
166
|
// Example: `/blog`, `/blog/page/1`, `/blog/page/2`
|
|
154
167
|
const totalCount = blogPosts.length;
|
|
168
|
+
const postsPerPage =
|
|
169
|
+
postsPerPageOption === 'ALL' ? totalCount : postsPerPageOption;
|
|
155
170
|
const numberOfPages = Math.ceil(totalCount / postsPerPage);
|
|
156
|
-
const
|
|
157
|
-
siteConfig: {baseUrl = ''},
|
|
158
|
-
} = context;
|
|
159
|
-
const basePageUrl = normalizeUrl([baseUrl, routeBasePath]);
|
|
171
|
+
const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
|
|
160
172
|
|
|
161
173
|
const blogListPaginated: BlogPaginated[] = [];
|
|
162
174
|
|
|
163
175
|
function blogPaginationPermalink(page: number) {
|
|
164
176
|
return page > 0
|
|
165
|
-
? normalizeUrl([
|
|
166
|
-
:
|
|
177
|
+
? normalizeUrl([baseBlogUrl, `page/${page + 1}`])
|
|
178
|
+
: baseBlogUrl;
|
|
167
179
|
}
|
|
168
180
|
|
|
169
181
|
for (let page = 0; page < numberOfPages; page += 1) {
|
|
@@ -179,8 +191,8 @@ export default function pluginContentBlog(
|
|
|
179
191
|
page < numberOfPages - 1
|
|
180
192
|
? blogPaginationPermalink(page + 1)
|
|
181
193
|
: null,
|
|
182
|
-
blogDescription
|
|
183
|
-
blogTitle
|
|
194
|
+
blogDescription,
|
|
195
|
+
blogTitle,
|
|
184
196
|
},
|
|
185
197
|
items: blogPosts
|
|
186
198
|
.slice(page * postsPerPage, (page + 1) * postsPerPage)
|
|
@@ -188,46 +200,15 @@ export default function pluginContentBlog(
|
|
|
188
200
|
});
|
|
189
201
|
}
|
|
190
202
|
|
|
191
|
-
const blogTags: BlogTags =
|
|
192
|
-
const tagsPath = normalizeUrl([basePageUrl, 'tags']);
|
|
193
|
-
blogPosts.forEach((blogPost) => {
|
|
194
|
-
const {tags} = blogPost.metadata;
|
|
195
|
-
if (!tags || tags.length === 0) {
|
|
196
|
-
// TODO: Extract tags out into a separate plugin.
|
|
197
|
-
// eslint-disable-next-line no-param-reassign
|
|
198
|
-
blogPost.metadata.tags = [];
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
203
|
+
const blogTags: BlogTags = getBlogTags(blogPosts);
|
|
201
204
|
|
|
202
|
-
|
|
203
|
-
blogPost.metadata.tags = tags.map((tag) => {
|
|
204
|
-
if (typeof tag === 'string') {
|
|
205
|
-
const normalizedTag = kebabCase(tag);
|
|
206
|
-
const permalink = normalizeUrl([tagsPath, normalizedTag]);
|
|
207
|
-
if (!blogTags[normalizedTag]) {
|
|
208
|
-
blogTags[normalizedTag] = {
|
|
209
|
-
// Will only use the name of the first occurrence of the tag.
|
|
210
|
-
name: tag.toLowerCase(),
|
|
211
|
-
items: [],
|
|
212
|
-
permalink,
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
blogTags[normalizedTag].items.push(blogPost.id);
|
|
217
|
-
|
|
218
|
-
return {
|
|
219
|
-
label: tag,
|
|
220
|
-
permalink,
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
return tag;
|
|
224
|
-
});
|
|
225
|
-
});
|
|
205
|
+
const tagsPath = normalizeUrl([baseBlogUrl, tagsBasePath]);
|
|
226
206
|
|
|
227
207
|
const blogTagsListPath =
|
|
228
208
|
Object.keys(blogTags).length > 0 ? tagsPath : null;
|
|
229
209
|
|
|
230
210
|
return {
|
|
211
|
+
blogSidebarTitle,
|
|
231
212
|
blogPosts,
|
|
232
213
|
blogListPaginated,
|
|
233
214
|
blogTags,
|
|
@@ -245,10 +226,13 @@ export default function pluginContentBlog(
|
|
|
245
226
|
blogPostComponent,
|
|
246
227
|
blogTagsListComponent,
|
|
247
228
|
blogTagsPostsComponent,
|
|
229
|
+
routeBasePath,
|
|
230
|
+
archiveBasePath,
|
|
248
231
|
} = options;
|
|
249
232
|
|
|
250
233
|
const {addRoute, createData} = actions;
|
|
251
234
|
const {
|
|
235
|
+
blogSidebarTitle,
|
|
252
236
|
blogPosts,
|
|
253
237
|
blogListPaginated,
|
|
254
238
|
blogTags,
|
|
@@ -262,6 +246,26 @@ export default function pluginContentBlog(
|
|
|
262
246
|
? blogPosts
|
|
263
247
|
: take(blogPosts, options.blogSidebarCount);
|
|
264
248
|
|
|
249
|
+
const archiveUrl = normalizeUrl([
|
|
250
|
+
baseUrl,
|
|
251
|
+
routeBasePath,
|
|
252
|
+
archiveBasePath,
|
|
253
|
+
]);
|
|
254
|
+
|
|
255
|
+
// creates a blog archive route
|
|
256
|
+
const archiveProp = await createData(
|
|
257
|
+
`${docuHash(archiveUrl)}.json`,
|
|
258
|
+
JSON.stringify({blogPosts}, null, 2),
|
|
259
|
+
);
|
|
260
|
+
addRoute({
|
|
261
|
+
path: archiveUrl,
|
|
262
|
+
component: '@theme/BlogArchivePage',
|
|
263
|
+
exact: true,
|
|
264
|
+
modules: {
|
|
265
|
+
archive: aliasedSource(archiveProp),
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
|
|
265
269
|
// This prop is useful to provide the blog list sidebar
|
|
266
270
|
const sidebarProp = await createData(
|
|
267
271
|
// Note that this created data path must be in sync with
|
|
@@ -269,7 +273,7 @@ export default function pluginContentBlog(
|
|
|
269
273
|
`blog-post-list-prop-${pluginId}.json`,
|
|
270
274
|
JSON.stringify(
|
|
271
275
|
{
|
|
272
|
-
title:
|
|
276
|
+
title: blogSidebarTitle,
|
|
273
277
|
items: sidebarBlogPosts.map((blogPost) => ({
|
|
274
278
|
title: blogPost.metadata.title,
|
|
275
279
|
permalink: blogPost.metadata.permalink,
|
|
@@ -350,6 +354,7 @@ export default function pluginContentBlog(
|
|
|
350
354
|
Object.keys(blogTags).map(async (tag) => {
|
|
351
355
|
const {name, items, permalink} = blogTags[tag];
|
|
352
356
|
|
|
357
|
+
// Refactor all this, see docs implementation
|
|
353
358
|
tagsModule[tag] = {
|
|
354
359
|
allTagsPath: blogTagsListPath,
|
|
355
360
|
slug: tag,
|
|
@@ -406,6 +411,10 @@ export default function pluginContentBlog(
|
|
|
406
411
|
}
|
|
407
412
|
},
|
|
408
413
|
|
|
414
|
+
translateContent({content, translationFiles}) {
|
|
415
|
+
return translateContent(content, translationFiles);
|
|
416
|
+
},
|
|
417
|
+
|
|
409
418
|
configureWebpack(
|
|
410
419
|
_config: Configuration,
|
|
411
420
|
isServer: boolean,
|
|
@@ -436,6 +445,7 @@ export default function pluginContentBlog(
|
|
|
436
445
|
},
|
|
437
446
|
};
|
|
438
447
|
|
|
448
|
+
const contentDirs = getContentPathList(contentPaths);
|
|
439
449
|
return {
|
|
440
450
|
resolve: {
|
|
441
451
|
alias: {
|
|
@@ -446,7 +456,7 @@ export default function pluginContentBlog(
|
|
|
446
456
|
rules: [
|
|
447
457
|
{
|
|
448
458
|
test: /(\.mdx?)$/,
|
|
449
|
-
include:
|
|
459
|
+
include: contentDirs
|
|
450
460
|
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
|
451
461
|
.map(addTrailingPathSeparator),
|
|
452
462
|
use: [
|
|
@@ -459,9 +469,13 @@ export default function pluginContentBlog(
|
|
|
459
469
|
beforeDefaultRemarkPlugins,
|
|
460
470
|
beforeDefaultRehypePlugins,
|
|
461
471
|
staticDir: path.join(siteDir, STATIC_DIR_NAME),
|
|
462
|
-
|
|
463
|
-
|
|
472
|
+
isMDXPartial: createAbsoluteFilePathMatcher(
|
|
473
|
+
options.exclude,
|
|
474
|
+
contentDirs,
|
|
475
|
+
),
|
|
464
476
|
metadataPath: (mdxPath: string) => {
|
|
477
|
+
// Note that metadataPath must be the same/in-sync as
|
|
478
|
+
// the path from createData for each MDX.
|
|
465
479
|
const aliasedPath = aliasedSitePath(mdxPath, siteDir);
|
|
466
480
|
return path.join(
|
|
467
481
|
dataDir,
|
|
@@ -471,6 +485,22 @@ export default function pluginContentBlog(
|
|
|
471
485
|
// For blog posts a title in markdown is always removed
|
|
472
486
|
// Blog posts title are rendered separately
|
|
473
487
|
removeContentTitle: true,
|
|
488
|
+
|
|
489
|
+
// Assets allow to convert some relative images paths to require() calls
|
|
490
|
+
createAssets: ({
|
|
491
|
+
frontMatter,
|
|
492
|
+
metadata,
|
|
493
|
+
}: {
|
|
494
|
+
frontMatter: BlogPostFrontMatter;
|
|
495
|
+
metadata: MetaData;
|
|
496
|
+
}): Assets => {
|
|
497
|
+
return {
|
|
498
|
+
image: frontMatter.image,
|
|
499
|
+
authorsImageUrls: metadata.authors.map(
|
|
500
|
+
(author) => author.imageURL,
|
|
501
|
+
),
|
|
502
|
+
};
|
|
503
|
+
},
|
|
474
504
|
},
|
|
475
505
|
},
|
|
476
506
|
{
|
|
@@ -485,7 +515,7 @@ export default function pluginContentBlog(
|
|
|
485
515
|
},
|
|
486
516
|
|
|
487
517
|
async postBuild({outDir}: Props) {
|
|
488
|
-
if (!options.feedOptions
|
|
518
|
+
if (!options.feedOptions.type) {
|
|
489
519
|
return;
|
|
490
520
|
}
|
|
491
521
|
|
|
@@ -524,20 +554,17 @@ export default function pluginContentBlog(
|
|
|
524
554
|
}
|
|
525
555
|
|
|
526
556
|
const feedTypes = options.feedOptions.type;
|
|
527
|
-
const
|
|
528
|
-
siteConfig: {title},
|
|
529
|
-
baseUrl,
|
|
530
|
-
} = context;
|
|
557
|
+
const feedTitle = options.feedOptions.title ?? context.siteConfig.title;
|
|
531
558
|
const feedsConfig = {
|
|
532
559
|
rss: {
|
|
533
560
|
type: 'application/rss+xml',
|
|
534
561
|
path: 'rss.xml',
|
|
535
|
-
title: `${
|
|
562
|
+
title: `${feedTitle} RSS Feed`,
|
|
536
563
|
},
|
|
537
564
|
atom: {
|
|
538
565
|
type: 'application/atom+xml',
|
|
539
566
|
path: 'atom.xml',
|
|
540
|
-
title: `${
|
|
567
|
+
title: `${feedTitle} Atom Feed`,
|
|
541
568
|
},
|
|
542
569
|
};
|
|
543
570
|
const headTags: HtmlTags = [];
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
declare module '@docusaurus/plugin-content-blog' {
|
|
9
|
+
export type Options = Partial<import('./types').UserPluginOptions>;
|
|
10
|
+
}
|
|
10
11
|
|
|
11
12
|
declare module '@theme/BlogSidebar' {
|
|
12
13
|
export type BlogSidebarItem = {title: string; permalink: string};
|
|
@@ -15,32 +16,20 @@ declare module '@theme/BlogSidebar' {
|
|
|
15
16
|
items: BlogSidebarItem[];
|
|
16
17
|
};
|
|
17
18
|
|
|
18
|
-
export
|
|
19
|
+
export interface Props {
|
|
19
20
|
readonly sidebar: BlogSidebar;
|
|
20
|
-
}
|
|
21
|
+
}
|
|
21
22
|
|
|
22
23
|
const BlogSidebar: (props: Props) => JSX.Element;
|
|
23
24
|
export default BlogSidebar;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
declare module '@theme/BlogPostPage' {
|
|
27
|
-
import type {TOCItem} from '@docusaurus/types';
|
|
28
28
|
import type {BlogSidebar} from '@theme/BlogSidebar';
|
|
29
|
+
import type {TOCItem} from '@docusaurus/types';
|
|
29
30
|
|
|
30
|
-
export type FrontMatter =
|
|
31
|
-
|
|
32
|
-
readonly author?: string;
|
|
33
|
-
readonly image?: string;
|
|
34
|
-
readonly tags?: readonly string[];
|
|
35
|
-
readonly keywords?: readonly string[];
|
|
36
|
-
readonly author_url?: string;
|
|
37
|
-
readonly authorURL?: string;
|
|
38
|
-
readonly author_title?: string;
|
|
39
|
-
readonly authorTitle?: string;
|
|
40
|
-
readonly author_image_url?: string;
|
|
41
|
-
readonly authorImageURL?: string;
|
|
42
|
-
readonly hide_table_of_contents?: boolean;
|
|
43
|
-
};
|
|
31
|
+
export type FrontMatter = import('./blogFrontMatter').BlogPostFrontMatter;
|
|
32
|
+
export type Assets = import('./types').Assets;
|
|
44
33
|
|
|
45
34
|
export type Metadata = {
|
|
46
35
|
readonly title: string;
|
|
@@ -53,6 +42,7 @@ declare module '@theme/BlogPostPage' {
|
|
|
53
42
|
readonly truncated?: string;
|
|
54
43
|
readonly nextItem?: {readonly title: string; readonly permalink: string};
|
|
55
44
|
readonly prevItem?: {readonly title: string; readonly permalink: string};
|
|
45
|
+
readonly authors: import('./types').Author[];
|
|
56
46
|
readonly tags: readonly {
|
|
57
47
|
readonly label: string;
|
|
58
48
|
readonly permalink: string;
|
|
@@ -61,15 +51,16 @@ declare module '@theme/BlogPostPage' {
|
|
|
61
51
|
|
|
62
52
|
export type Content = {
|
|
63
53
|
readonly frontMatter: FrontMatter;
|
|
54
|
+
readonly assets: Assets;
|
|
64
55
|
readonly metadata: Metadata;
|
|
65
56
|
readonly toc: readonly TOCItem[];
|
|
66
57
|
(): JSX.Element;
|
|
67
58
|
};
|
|
68
59
|
|
|
69
|
-
export
|
|
60
|
+
export interface Props {
|
|
70
61
|
readonly sidebar: BlogSidebar;
|
|
71
62
|
readonly content: Content;
|
|
72
|
-
}
|
|
63
|
+
}
|
|
73
64
|
|
|
74
65
|
const BlogPostPage: (props: Props) => JSX.Element;
|
|
75
66
|
export default BlogPostPage;
|
|
@@ -79,10 +70,6 @@ declare module '@theme/BlogListPage' {
|
|
|
79
70
|
import type {Content} from '@theme/BlogPostPage';
|
|
80
71
|
import type {BlogSidebar} from '@theme/BlogSidebar';
|
|
81
72
|
|
|
82
|
-
export type Item = {
|
|
83
|
-
readonly content: () => JSX.Element;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
73
|
export type Metadata = {
|
|
87
74
|
readonly blogTitle: string;
|
|
88
75
|
readonly blogDescription: string;
|
|
@@ -95,11 +82,11 @@ declare module '@theme/BlogListPage' {
|
|
|
95
82
|
readonly totalPages: number;
|
|
96
83
|
};
|
|
97
84
|
|
|
98
|
-
export
|
|
85
|
+
export interface Props {
|
|
99
86
|
readonly sidebar: BlogSidebar;
|
|
100
87
|
readonly metadata: Metadata;
|
|
101
88
|
readonly items: readonly {readonly content: Content}[];
|
|
102
|
-
}
|
|
89
|
+
}
|
|
103
90
|
|
|
104
91
|
const BlogListPage: (props: Props) => JSX.Element;
|
|
105
92
|
export default BlogListPage;
|
|
@@ -116,10 +103,10 @@ declare module '@theme/BlogTagsListPage' {
|
|
|
116
103
|
slug: string;
|
|
117
104
|
};
|
|
118
105
|
|
|
119
|
-
export
|
|
106
|
+
export interface Props {
|
|
120
107
|
readonly sidebar: BlogSidebar;
|
|
121
108
|
readonly tags: Readonly<Record<string, Tag>>;
|
|
122
|
-
}
|
|
109
|
+
}
|
|
123
110
|
|
|
124
111
|
const BlogTagsListPage: (props: Props) => JSX.Element;
|
|
125
112
|
export default BlogTagsListPage;
|
|
@@ -130,9 +117,26 @@ declare module '@theme/BlogTagsPostsPage' {
|
|
|
130
117
|
import type {Tag} from '@theme/BlogTagsListPage';
|
|
131
118
|
import type {Content} from '@theme/BlogPostPage';
|
|
132
119
|
|
|
133
|
-
export
|
|
120
|
+
export interface Props {
|
|
134
121
|
readonly sidebar: BlogSidebar;
|
|
135
122
|
readonly metadata: Tag;
|
|
136
123
|
readonly items: readonly {readonly content: Content}[];
|
|
137
|
-
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const BlogTagsPostsPage: (props: Props) => JSX.Element;
|
|
127
|
+
export default BlogTagsPostsPage;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
declare module '@theme/BlogArchivePage' {
|
|
131
|
+
import type {Content} from '@theme/BlogPostPage';
|
|
132
|
+
|
|
133
|
+
export type ArchiveBlogPost = Content;
|
|
134
|
+
|
|
135
|
+
export interface Props {
|
|
136
|
+
readonly archive: {
|
|
137
|
+
readonly blogPosts: readonly ArchiveBlogPost[];
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export default function BlogArchivePage(props: Props): JSX.Element;
|
|
138
142
|
}
|
|
@@ -12,9 +12,11 @@ import {
|
|
|
12
12
|
AdmonitionsSchema,
|
|
13
13
|
URISchema,
|
|
14
14
|
} from '@docusaurus/utils-validation';
|
|
15
|
+
import {GlobExcludeDefault} from '@docusaurus/utils';
|
|
16
|
+
import {PluginOptions} from './types';
|
|
15
17
|
|
|
16
|
-
export const DEFAULT_OPTIONS = {
|
|
17
|
-
feedOptions: {type: ['rss', 'atom']},
|
|
18
|
+
export const DEFAULT_OPTIONS: PluginOptions = {
|
|
19
|
+
feedOptions: {type: ['rss', 'atom'], copyright: ''},
|
|
18
20
|
beforeDefaultRehypePlugins: [],
|
|
19
21
|
beforeDefaultRemarkPlugins: [],
|
|
20
22
|
admonitions: {},
|
|
@@ -31,22 +33,28 @@ export const DEFAULT_OPTIONS = {
|
|
|
31
33
|
blogSidebarCount: 5,
|
|
32
34
|
blogSidebarTitle: 'Recent posts',
|
|
33
35
|
postsPerPage: 10,
|
|
34
|
-
include: ['
|
|
36
|
+
include: ['**/*.{md,mdx}'],
|
|
37
|
+
exclude: GlobExcludeDefault,
|
|
35
38
|
routeBasePath: 'blog',
|
|
39
|
+
tagsBasePath: 'tags',
|
|
40
|
+
archiveBasePath: 'archive',
|
|
36
41
|
path: 'blog',
|
|
37
42
|
editLocalizedFiles: false,
|
|
43
|
+
authorsMapPath: 'authors.yml',
|
|
38
44
|
};
|
|
39
45
|
|
|
40
|
-
export const PluginOptionSchema = Joi.object({
|
|
46
|
+
export const PluginOptionSchema = Joi.object<PluginOptions>({
|
|
41
47
|
path: Joi.string().default(DEFAULT_OPTIONS.path),
|
|
48
|
+
archiveBasePath: Joi.string().default(DEFAULT_OPTIONS.archiveBasePath),
|
|
42
49
|
routeBasePath: Joi.string()
|
|
43
50
|
// '' not allowed, see https://github.com/facebook/docusaurus/issues/3374
|
|
44
51
|
// .allow('')
|
|
45
52
|
.default(DEFAULT_OPTIONS.routeBasePath),
|
|
53
|
+
tagsBasePath: Joi.string().default(DEFAULT_OPTIONS.tagsBasePath),
|
|
46
54
|
include: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.include),
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
.min(1)
|
|
55
|
+
exclude: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.exclude),
|
|
56
|
+
postsPerPage: Joi.alternatives()
|
|
57
|
+
.try(Joi.equal('ALL').required(), Joi.number().integer().min(1).required())
|
|
50
58
|
.default(DEFAULT_OPTIONS.postsPerPage),
|
|
51
59
|
blogListComponent: Joi.string().default(DEFAULT_OPTIONS.blogListComponent),
|
|
52
60
|
blogPostComponent: Joi.string().default(DEFAULT_OPTIONS.blogPostComponent),
|
|
@@ -61,7 +69,7 @@ export const PluginOptionSchema = Joi.object({
|
|
|
61
69
|
.allow('')
|
|
62
70
|
.default(DEFAULT_OPTIONS.blogDescription),
|
|
63
71
|
blogSidebarCount: Joi.alternatives()
|
|
64
|
-
.try(Joi.equal('ALL').required(), Joi.number().required())
|
|
72
|
+
.try(Joi.equal('ALL').required(), Joi.number().integer().min(0).required())
|
|
65
73
|
.default(DEFAULT_OPTIONS.blogSidebarCount),
|
|
66
74
|
blogSidebarTitle: Joi.string().default(DEFAULT_OPTIONS.blogSidebarTitle),
|
|
67
75
|
showReadingTime: Joi.bool().default(DEFAULT_OPTIONS.showReadingTime),
|
|
@@ -94,7 +102,15 @@ export const PluginOptionSchema = Joi.object({
|
|
|
94
102
|
.default(DEFAULT_OPTIONS.feedOptions.type),
|
|
95
103
|
title: Joi.string().allow(''),
|
|
96
104
|
description: Joi.string().allow(''),
|
|
97
|
-
|
|
105
|
+
// only add default value when user actually wants a feed (type is not null)
|
|
106
|
+
copyright: Joi.when('type', {
|
|
107
|
+
is: Joi.any().valid(null),
|
|
108
|
+
then: Joi.string().optional(),
|
|
109
|
+
otherwise: Joi.string()
|
|
110
|
+
.allow('')
|
|
111
|
+
.default(DEFAULT_OPTIONS.feedOptions.copyright),
|
|
112
|
+
}),
|
|
98
113
|
language: Joi.string(),
|
|
99
114
|
}).default(DEFAULT_OPTIONS.feedOptions),
|
|
115
|
+
authorsMapPath: Joi.string().default(DEFAULT_OPTIONS.authorsMapPath),
|
|
100
116
|
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {BlogContent, PluginOptions, BlogPaginated} from './types';
|
|
9
|
+
import type {TranslationFileContent, TranslationFiles} from '@docusaurus/types';
|
|
10
|
+
|
|
11
|
+
function translateListPage(
|
|
12
|
+
blogListPaginated: BlogPaginated[],
|
|
13
|
+
translations: TranslationFileContent,
|
|
14
|
+
) {
|
|
15
|
+
return blogListPaginated.map((page) => {
|
|
16
|
+
const {items, metadata} = page;
|
|
17
|
+
return {
|
|
18
|
+
items,
|
|
19
|
+
metadata: {
|
|
20
|
+
...metadata,
|
|
21
|
+
blogTitle: translations.title.message,
|
|
22
|
+
blogDescription: translations.description.message,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function getTranslationFiles(options: PluginOptions): TranslationFiles {
|
|
29
|
+
return [
|
|
30
|
+
{
|
|
31
|
+
path: 'options',
|
|
32
|
+
content: {
|
|
33
|
+
title: {
|
|
34
|
+
message: options.blogTitle,
|
|
35
|
+
description: 'The title for the blog used in SEO',
|
|
36
|
+
},
|
|
37
|
+
description: {
|
|
38
|
+
message: options.blogDescription,
|
|
39
|
+
description: 'The description for the blog used in SEO',
|
|
40
|
+
},
|
|
41
|
+
'sidebar.title': {
|
|
42
|
+
message: options.blogSidebarTitle,
|
|
43
|
+
description: 'The label for the left sidebar',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function translateContent(
|
|
51
|
+
content: BlogContent,
|
|
52
|
+
translationFiles: TranslationFiles,
|
|
53
|
+
): BlogContent {
|
|
54
|
+
const [{content: optonsTranslations}] = translationFiles;
|
|
55
|
+
return {
|
|
56
|
+
...content,
|
|
57
|
+
blogSidebarTitle: optonsTranslations['sidebar.title'].message,
|
|
58
|
+
blogListPaginated: translateListPage(
|
|
59
|
+
content.blogListPaginated,
|
|
60
|
+
optonsTranslations,
|
|
61
|
+
),
|
|
62
|
+
};
|
|
63
|
+
}
|