feat(v2): add edit url in post page (#2524)

* Add edit page url in docs

* feat(v2): Create EditPage component

* feat(v2): Improve component

* Add test

* çhore(v2): update description

* çhore(v2): update url

* fix(v2): test

* fix(v2): test

* feat(v2): change the prop of EditPage component

* chore(v2): Remove packages

* feat(v2): Update old tests

* chore(v2): fix package

* fix(v2): fix editUrl

* docs(v2): document editUrl

* --

* --

Co-authored-by: Yangshun Tay <tay.yang.shun@gmail.com>
This commit is contained in:
Fanny 2020-04-05 06:34:48 -03:00 committed by GitHub
parent 7bc7241ee4
commit 5e664a1f26
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 72 additions and 12 deletions

View file

@ -28,6 +28,8 @@ describe('loadBlog', () => {
} as LoadContext, } as LoadContext,
{ {
path: pluginPath, path: pluginPath,
editUrl:
'https://github.com/facebook/docusaurus/edit/master/website-1x',
}, },
); );
const {blogPosts} = await plugin.loadContent(); const {blogPosts} = await plugin.loadContent();
@ -50,12 +52,15 @@ describe('loadBlog', () => {
...blogPosts.find(v => v.metadata.title === 'date-matter').metadata, ...blogPosts.find(v => v.metadata.title === 'date-matter').metadata,
...{prevItem: undefined}, ...{prevItem: undefined},
}).toEqual({ }).toEqual({
editUrl:
'https://github.com/facebook/docusaurus/edit/master/website-1x/blog/date-matter.md',
permalink: '/blog/2019/01/01/date-matter', permalink: '/blog/2019/01/01/date-matter',
readingTime: 0.02, readingTime: 0.02,
source: path.join('@site', pluginPath, 'date-matter.md'), source: path.join('@site', pluginPath, 'date-matter.md'),
title: 'date-matter', title: 'date-matter',
description: `date inside front matter`, description: `date inside front matter`,
date: new Date('2019-01-01'), date: new Date('2019-01-01'),
prevItem: undefined,
tags: [], tags: [],
nextItem: { nextItem: {
permalink: '/blog/2018/12/14/Happy-First-Birthday-Slash', permalink: '/blog/2018/12/14/Happy-First-Birthday-Slash',
@ -68,6 +73,8 @@ describe('loadBlog', () => {
blogPosts.find(v => v.metadata.title === 'Happy 1st Birthday Slash!') blogPosts.find(v => v.metadata.title === 'Happy 1st Birthday Slash!')
.metadata, .metadata,
).toEqual({ ).toEqual({
editUrl:
'https://github.com/facebook/docusaurus/edit/master/website-1x/blog/2018-12-14-Happy-First-Birthday-Slash.md',
permalink: '/blog/2018/12/14/Happy-First-Birthday-Slash', permalink: '/blog/2018/12/14/Happy-First-Birthday-Slash',
readingTime: 0.01, readingTime: 0.01,
source: path.join( source: path.join(
@ -90,6 +97,8 @@ describe('loadBlog', () => {
...blogPosts.find(v => v.metadata.title === 'no date').metadata, ...blogPosts.find(v => v.metadata.title === 'no date').metadata,
...{prevItem: undefined}, ...{prevItem: undefined},
}).toEqual({ }).toEqual({
editUrl:
'https://github.com/facebook/docusaurus/edit/master/website-1x/blog/no date.md',
permalink: noDatePermalink, permalink: noDatePermalink,
readingTime: 0.01, readingTime: 0.01,
source: noDateSource, source: noDateSource,
@ -97,6 +106,7 @@ describe('loadBlog', () => {
description: `no date`, description: `no date`,
date: noDateSourceBirthTime, date: noDateSourceBirthTime,
tags: [], tags: [],
prevItem: undefined,
nextItem: { nextItem: {
permalink: '/blog/2020/02/27/draft', permalink: '/blog/2020/02/27/draft',
title: 'draft', title: 'draft',

View file

@ -11,7 +11,12 @@ import path from 'path';
import readingTime from 'reading-time'; import readingTime from 'reading-time';
import {Feed} from 'feed'; import {Feed} from 'feed';
import {PluginOptions, BlogPost, DateLink} from './types'; import {PluginOptions, BlogPost, DateLink} from './types';
import {parse, normalizeUrl, aliasedSitePath} from '@docusaurus/utils'; import {
parse,
normalizeUrl,
aliasedSitePath,
getEditUrl,
} from '@docusaurus/utils';
import {LoadContext} from '@docusaurus/types'; import {LoadContext} from '@docusaurus/types';
export function truncate(fileString: string, truncateMarker: RegExp) { export function truncate(fileString: string, truncateMarker: RegExp) {
@ -86,7 +91,13 @@ export async function generateBlogPosts(
{siteConfig, siteDir}: LoadContext, {siteConfig, siteDir}: LoadContext,
options: PluginOptions, options: PluginOptions,
) { ) {
const {include, routeBasePath, truncateMarker, showReadingTime} = options; const {
include,
routeBasePath,
truncateMarker,
showReadingTime,
editUrl,
} = options;
if (!fs.existsSync(blogDir)) { if (!fs.existsSync(blogDir)) {
return []; return [];
@ -103,8 +114,12 @@ export async function generateBlogPosts(
blogFiles.map(async (relativeSource: string) => { blogFiles.map(async (relativeSource: string) => {
const source = path.join(blogDir, relativeSource); const source = path.join(blogDir, relativeSource);
const aliasedSource = aliasedSitePath(source, siteDir); const aliasedSource = aliasedSitePath(source, siteDir);
const refDir = path.parse(blogDir).dir;
const relativePath = path.relative(refDir, source);
const blogFileName = path.basename(relativeSource); const blogFileName = path.basename(relativeSource);
const editBlogUrl = getEditUrl(relativePath, editUrl);
const fileString = await fs.readFile(source, 'utf-8'); const fileString = await fs.readFile(source, 'utf-8');
const {frontMatter, content, excerpt} = parse(fileString); const {frontMatter, content, excerpt} = parse(fileString);
@ -140,6 +155,7 @@ export async function generateBlogPosts(
routeBasePath, routeBasePath,
frontMatter.id || toUrl({date, link: linkName}), frontMatter.id || toUrl({date, link: linkName}),
]), ]),
editUrl: editBlogUrl,
source: aliasedSource, source: aliasedSource,
description: frontMatter.description || excerpt, description: frontMatter.description || excerpt,
date, date,

View file

@ -43,6 +43,7 @@ const DEFAULT_OPTIONS: PluginOptions = {
showReadingTime: true, showReadingTime: true,
remarkPlugins: [], remarkPlugins: [],
rehypePlugins: [], rehypePlugins: [],
editUrl: undefined,
truncateMarker: /<!--\s*(truncate)\s*-->/, // Regex. truncateMarker: /<!--\s*(truncate)\s*-->/, // Regex.
}; };

View file

@ -39,6 +39,7 @@ export interface PluginOptions {
copyright: string; copyright: string;
language?: string; language?: string;
}; };
editUrl?: string;
} }
export interface BlogTags { export interface BlogTags {
@ -82,6 +83,7 @@ export interface MetaData {
prevItem?: Paginator; prevItem?: Paginator;
nextItem?: Paginator; nextItem?: Paginator;
truncated: boolean; truncated: boolean;
editUrl?: string;
} }
export interface Paginator { export interface Paginator {

View file

@ -11,7 +11,7 @@ import {
parse, parse,
aliasedSitePath, aliasedSitePath,
normalizeUrl, normalizeUrl,
posixPath, getEditUrl,
} from '@docusaurus/utils'; } from '@docusaurus/utils';
import {LoadContext} from '@docusaurus/types'; import {LoadContext} from '@docusaurus/types';
@ -90,9 +90,7 @@ export default async function processMetadata({
const relativePath = path.relative(siteDir, filePath); const relativePath = path.relative(siteDir, filePath);
const docsEditUrl = editUrl const docsEditUrl = getEditUrl(relativePath, editUrl);
? normalizeUrl([editUrl, posixPath(relativePath)])
: undefined;
const {frontMatter = {}, excerpt} = parse(await fileStringPromise); const {frontMatter = {}, excerpt} = parse(await fileStringPromise);
const {sidebar_label, custom_edit_url} = frontMatter; const {sidebar_label, custom_edit_url} = frontMatter;

View file

@ -14,8 +14,10 @@ import BlogPostPaginator from '@theme/BlogPostPaginator';
function BlogPostPage(props) { function BlogPostPage(props) {
const {content: BlogPostContents} = props; const {content: BlogPostContents} = props;
const {frontMatter, metadata} = BlogPostContents; const {frontMatter, metadata} = BlogPostContents;
const {title, description, nextItem, prevItem, editUrl} = metadata;
return ( return (
<Layout title={metadata.title} description={metadata.description}> <Layout title={title} description={description}>
{BlogPostContents && ( {BlogPostContents && (
<div className="container margin-vert--xl"> <div className="container margin-vert--xl">
<div className="row"> <div className="row">
@ -26,12 +28,30 @@ function BlogPostPage(props) {
isBlogPostPage> isBlogPostPage>
<BlogPostContents /> <BlogPostContents />
</BlogPostItem> </BlogPostItem>
{(metadata.nextItem || metadata.prevItem) && ( <div>
{editUrl && (
<a href={editUrl} target="_blank" rel="noreferrer noopener">
<svg
fill="currentColor"
height="1.2em"
width="1.2em"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 40 40"
style={{
marginRight: '0.3em',
verticalAlign: 'sub',
}}>
<g>
<path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z" />
</g>
</svg>
Edit this page
</a>
)}
</div>
{(nextItem || prevItem) && (
<div className="margin-vert--xl"> <div className="margin-vert--xl">
<BlogPostPaginator <BlogPostPaginator nextItem={nextItem} prevItem={prevItem} />
nextItem={metadata.nextItem}
prevItem={metadata.prevItem}
/>
</div> </div>
)} )}
</div> </div>

View file

@ -273,3 +273,9 @@ export function aliasedSitePath(filePath: string, siteDir: string) {
// the '@site'. Let webpack loader resolve it. // the '@site'. Let webpack loader resolve it.
return `@site/${relativePath}`; return `@site/${relativePath}`;
} }
export function getEditUrl(fileRelativePath: string, editUrl?: string) {
return editUrl
? normalizeUrl([editUrl, posixPath(fileRelativePath)])
: undefined;
}

View file

@ -149,6 +149,11 @@ module.exports = {
* relative to site dir * relative to site dir
*/ */
path: 'blog', path: 'blog',
/**
* URL for editing a blog post, example: 'https://github.com/facebook/docusaurus/edit/master/website/blog/'
*/
editUrl:
'https://github.com/facebook/docusaurus/edit/master/website/blog/',
/** /**
* URL route for the blog section of your site * URL route for the blog section of your site
* do not include trailing slash * do not include trailing slash

View file

@ -46,6 +46,8 @@ module.exports = {
}, },
blog: { blog: {
path: '../website-1.x/blog', path: '../website-1.x/blog',
editUrl:
'https://github.com/facebook/docusaurus/edit/master/website-1.x/',
postsPerPage: 3, postsPerPage: 3,
feedOptions: { feedOptions: {
type: 'all', type: 'all',