feat(v2): meta description (#1447)

* feat(v2): meta description

* add description for blog as well

* fix non-descriptive text link

* remove font awesome

* switch front-matter -> gray-matter
This commit is contained in:
Endi 2019-05-10 22:37:56 +07:00 committed by GitHub
parent 34195e4c30
commit 6136fbe1d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 82 additions and 58 deletions

View file

@ -10,9 +10,9 @@
"dependencies": { "dependencies": {
"@docusaurus/mdx-loader": "^2.0.0-alpha.13", "@docusaurus/mdx-loader": "^2.0.0-alpha.13",
"@docusaurus/utils": "^2.0.0-alpha.13", "@docusaurus/utils": "^2.0.0-alpha.13",
"front-matter": "^3.0.1",
"fs-extra": "^7.0.1", "fs-extra": "^7.0.1",
"globby": "^9.1.0", "globby": "^9.1.0",
"gray-matter": "^4.0.2",
"loader-utils": "^1.2.3" "loader-utils": "^1.2.3"
}, },
"peerDependencies": { "peerDependencies": {

View file

@ -75,7 +75,7 @@ class DocusaurusPluginContentBlog {
); );
const fileString = await fs.readFile(source, 'utf-8'); const fileString = await fs.readFile(source, 'utf-8');
const {metadata: rawMetadata} = parse(fileString); const {metadata: rawMetadata, excerpt: description} = parse(fileString);
const metadata = { const metadata = {
permalink: normalizeUrl([ permalink: normalizeUrl([
@ -84,6 +84,7 @@ class DocusaurusPluginContentBlog {
fileToUrl(blogFileName), fileToUrl(blogFileName),
]), ]),
source, source,
description,
...rawMetadata, ...rawMetadata,
date, date,
}; };

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const fm = require('front-matter'); const matter = require('gray-matter');
const {parseQuery} = require('loader-utils'); const {parseQuery} = require('loader-utils');
const TRUNCATE_MARKER = /<!--\s*truncate\s*-->/; const TRUNCATE_MARKER = /<!--\s*truncate\s*-->/;
@ -14,7 +14,7 @@ module.exports = async function(fileString) {
const callback = this.async(); const callback = this.async();
// Extract content of markdown (without frontmatter). // Extract content of markdown (without frontmatter).
let {body: content} = fm(fileString); let {content} = matter(fileString);
// Truncate content if requested (e.g: file.md?truncated=true) // Truncate content if requested (e.g: file.md?truncated=true)
const {truncated} = this.resourceQuery && parseQuery(this.resourceQuery); const {truncated} = this.resourceQuery && parseQuery(this.resourceQuery);

View file

@ -17,7 +17,7 @@ function BlogListPage(props) {
} = props; } = props;
return ( return (
<Layout title="Blog"> <Layout title="Blog" description="Blog">
<div className="container margin-vert--xl"> <div className="container margin-vert--xl">
<div className="row"> <div className="row">
<div className="col col--6 col--offset-3"> <div className="col col--6 col--offset-3">

View file

@ -14,7 +14,7 @@ function BlogPostPage(props) {
const {content: BlogPostContents, metadata} = props; const {content: BlogPostContents, metadata} = props;
return ( return (
<Layout title={metadata.title}> <Layout title={metadata.title} description={metadata.description}>
{BlogPostContents && ( {BlogPostContents && (
<div className="container margin-vert--xl"> <div className="container margin-vert--xl">
<div className="row"> <div className="row">

View file

@ -11,9 +11,9 @@
"@babel/polyfill": "^7.4.0", "@babel/polyfill": "^7.4.0",
"@docusaurus/mdx-loader": "^2.0.0-alpha.13", "@docusaurus/mdx-loader": "^2.0.0-alpha.13",
"@docusaurus/utils": "^2.0.0-alpha.13", "@docusaurus/utils": "^2.0.0-alpha.13",
"front-matter": "^3.0.1",
"fs-extra": "^7.0.1", "fs-extra": "^7.0.1",
"globby": "^9.1.0", "globby": "^9.1.0",
"gray-matter": "^4.0.2",
"import-fresh": "^3.0.0", "import-fresh": "^3.0.0",
"loader-utils": "^1.2.3" "loader-utils": "^1.2.3"
}, },

View file

@ -1,6 +1,7 @@
--- ---
id: bar id: bar
title: Bar title: Bar
description: This is custom description
--- ---
# Remarkable # Remarkable

View file

@ -39,6 +39,7 @@ describe('loadDocs', () => {
sidebar: 'docs', sidebar: 'docs',
source: path.join(docsDir, 'hello.md'), source: path.join(docsDir, 'hello.md'),
title: 'Hello, World !', title: 'Hello, World !',
description: `Hi, Endilie here :)`,
}); });
expect(docsMetadata['foo/bar']).toEqual({ expect(docsMetadata['foo/bar']).toEqual({
category: 'Test', category: 'Test',
@ -49,6 +50,7 @@ describe('loadDocs', () => {
sidebar: 'docs', sidebar: 'docs',
source: path.join(docsDir, 'foo', 'bar.md'), source: path.join(docsDir, 'foo', 'bar.md'),
title: 'Bar', title: 'Bar',
description: 'This is custom description',
}); });
}); });
}); });

View file

@ -40,12 +40,14 @@ describe('processMetadata', () => {
permalink: '/docs/foo/bar', permalink: '/docs/foo/bar',
source: path.join(docsDir, sourceA), source: path.join(docsDir, sourceA),
title: 'Bar', title: 'Bar',
description: 'This is custom description',
}); });
expect(dataB).toEqual({ expect(dataB).toEqual({
id: 'hello', id: 'hello',
permalink: '/docs/hello', permalink: '/docs/hello',
source: path.join(docsDir, sourceB), source: path.join(docsDir, sourceB),
title: 'Hello, World !', title: 'Hello, World !',
description: `Hi, Endilie here :)`,
}); });
}); });
@ -57,6 +59,7 @@ describe('processMetadata', () => {
permalink: '/docs/endiliey/permalink', permalink: '/docs/endiliey/permalink',
source: path.join(docsDir, source), source: path.join(docsDir, source),
title: 'Permalink', title: 'Permalink',
description: 'This has a different permalink',
}); });
}); });
}); });

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const fm = require('front-matter'); const matter = require('gray-matter');
const {getOptions} = require('loader-utils'); const {getOptions} = require('loader-utils');
const {resolve} = require('url'); const {resolve} = require('url');
@ -17,7 +17,7 @@ module.exports = async function(fileString) {
const {docsDir, sourceToPermalink} = options; const {docsDir, sourceToPermalink} = options;
// Extract content of markdown (without frontmatter). // Extract content of markdown (without frontmatter).
const {body} = fm(fileString); let {content} = matter(fileString);
// Determine the source dir. e.g: /docs, /website/versioned_docs/version-1.0.0 // Determine the source dir. e.g: /docs, /website/versioned_docs/version-1.0.0
let sourceDir; let sourceDir;
@ -27,10 +27,9 @@ module.exports = async function(fileString) {
} }
// Replace internal markdown linking (except in fenced blocks). // Replace internal markdown linking (except in fenced blocks).
let content = body;
if (sourceDir) { if (sourceDir) {
let fencedBlock = false; let fencedBlock = false;
const lines = body.split('\n').map(line => { const lines = content.split('\n').map(line => {
if (line.trim().startsWith('```')) { if (line.trim().startsWith('```')) {
fencedBlock = !fencedBlock; fencedBlock = !fencedBlock;
} }

View file

@ -18,7 +18,7 @@ module.exports = async function processMetadata(
) { ) {
const filepath = path.resolve(refDir, source); const filepath = path.resolve(refDir, source);
const fileString = await fs.readFile(filepath, 'utf-8'); const fileString = await fs.readFile(filepath, 'utf-8');
const {metadata} = parse(fileString); const {metadata = {}, excerpt} = parse(fileString);
// Default id is the file name. // Default id is the file name.
if (!metadata.id) { if (!metadata.id) {
@ -33,6 +33,10 @@ module.exports = async function processMetadata(
metadata.title = metadata.id; metadata.title = metadata.id;
} }
if (!metadata.description) {
metadata.description = excerpt;
}
const dirName = path.dirname(source); const dirName = path.dirname(source);
if (dirName !== '.') { if (dirName !== '.') {
const prefix = dirName; const prefix = dirName;

View file

@ -14,13 +14,19 @@ import DocSidebar from '@theme/DocSidebar';
function DocPage(props) { function DocPage(props) {
const {route, docsMetadata, location} = props; const {route, docsMetadata, location} = props;
const {permalinkToId} = docsMetadata;
const id =
permalinkToId[location.pathname] ||
permalinkToId[location.pathname.replace(/\/$/, '')];
const metadata = docsMetadata.docs[id] || {};
const {sidebar, description} = metadata;
return ( return (
<Layout noFooter> <Layout noFooter description={description}>
<div className="container container--fluid"> <div className="container container--fluid">
<div className="row"> <div className="row">
<div className="col col--3"> <div className="col col--3">
<DocSidebar docsMetadata={docsMetadata} location={location} /> <DocSidebar docsMetadata={docsMetadata} sidebar={sidebar} />
</div> </div>
<div className="col col--9"> <div className="col col--9">
{renderRoutes(route.routes, {docsMetadata})} {renderRoutes(route.routes, {docsMetadata})}

View file

@ -12,13 +12,7 @@ import Link from '@docusaurus/Link'; // eslint-disable-line
import './styles.css'; import './styles.css';
function DocSidebar(props) { function DocSidebar(props) {
const {docsMetadata, location} = props; const {docsMetadata, sidebar} = props;
const id =
docsMetadata.permalinkToId[location.pathname] ||
docsMetadata.permalinkToId[location.pathname.replace(/\/$/, '')];
const metadata = docsMetadata.docs[id] || {};
const {sidebar} = metadata;
if (!sidebar) { if (!sidebar) {
return null; return null;

View file

@ -17,12 +17,16 @@ function Layout(props) {
const context = useDocusaurusContext(); const context = useDocusaurusContext();
const {siteConfig = {}} = context; const {siteConfig = {}} = context;
const {baseUrl, favicon, tagline, title: defaultTitle} = siteConfig; const {baseUrl, favicon, tagline, title: defaultTitle} = siteConfig;
const {children, title, noFooter} = props; const {children, title, noFooter, description} = props;
return ( return (
<React.Fragment> <React.Fragment>
<Head defaultTitle={`${defaultTitle} · ${tagline}`}> <Head defaultTitle={`${defaultTitle} · ${tagline}`}>
{title && <title>{`${title} · ${tagline}`}</title>} {title && <title>{`${title} · ${tagline}`}</title>}
{favicon && <link rel="shortcut icon" href={baseUrl + favicon} />} {favicon && <link rel="shortcut icon" href={baseUrl + favicon} />}
{description && <meta name="description" content={description} />}
{description && (
<meta property="og:description" content={description} />
)}
</Head> </Head>
<Navbar /> <Navbar />
{children} {children}

View file

@ -9,8 +9,8 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"escape-string-regexp": "^1.0.5", "escape-string-regexp": "^1.0.5",
"front-matter": "^3.0.1",
"fs-extra": "^7.0.0", "fs-extra": "^7.0.0",
"gray-matter": "^4.0.2",
"lodash": "^4.17.11" "lodash": "^4.17.11"
} }
} }

View file

@ -6,7 +6,7 @@
*/ */
const path = require('path'); const path = require('path');
const fm = require('front-matter'); const matter = require('gray-matter');
const {createHash} = require('crypto'); const {createHash} = require('crypto');
const _ = require(`lodash`); const _ = require(`lodash`);
@ -163,15 +163,19 @@ function getSubFolder(file, refDir) {
/** /**
* @param {string} fileString * @param {string} fileString
* @returns {*} * @returns {Object}
*/ */
function parse(fileString) { function parse(fileString) {
if (!fm.test(fileString)) { const {data: metadata, content, excerpt} = matter(fileString, {
return {metadata: null, content: fileString}; excerpt(file) {
} // eslint-disable-next-line no-param-reassign
const {attributes: metadata, body: content} = fm(fileString); file.excerpt = file.content
.trim()
return {metadata, content}; .split('\n', 1)
.shift();
},
});
return {metadata, content, excerpt};
} }
/** /**

View file

@ -47,7 +47,6 @@
"ejs": "^2.6.1", "ejs": "^2.6.1",
"envinfo": "^7.2.0", "envinfo": "^7.2.0",
"express": "^4.16.4", "express": "^4.16.4",
"front-matter": "^3.0.1",
"fs-extra": "^7.0.0", "fs-extra": "^7.0.0",
"globby": "^9.1.0", "globby": "^9.1.0",
"html-webpack-plugin": "^4.0.0-beta.5", "html-webpack-plugin": "^4.0.0-beta.5",

View file

@ -19,13 +19,6 @@ function App() {
<DocusaurusContext.Provider value={{siteConfig}}> <DocusaurusContext.Provider value={{siteConfig}}>
{/* TODO: this link stylesheet to infima is temporary */} {/* TODO: this link stylesheet to infima is temporary */}
<Head> <Head>
<link
crossOrigin="anonymous"
href="https://use.fontawesome.com/releases/v5.8.1/css/all.css"
integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf"
preload
rel="stylesheet"
/>
<link <link
href="https://infima-dev.netlify.com/css/default/default.min.css" href="https://infima-dev.netlify.com/css/default/default.min.css"
preload preload

View file

@ -13,12 +13,16 @@ function Layout(props) {
const context = useDocusaurusContext(); const context = useDocusaurusContext();
const {siteConfig = {}} = context; const {siteConfig = {}} = context;
const {baseUrl, favicon, tagline, title: defaultTitle} = siteConfig; const {baseUrl, favicon, tagline, title: defaultTitle} = siteConfig;
const {children, title} = props; const {children, title, description} = props;
return ( return (
<React.Fragment> <React.Fragment>
<Head defaultTitle={`${defaultTitle} · ${tagline}`}> <Head defaultTitle={`${defaultTitle} · ${tagline}`}>
{title && <title>{`${title} · ${tagline}`}</title>} {title && <title>{`${title} · ${tagline}`}</title>}
{favicon && <link rel="shortcut icon" href={baseUrl + favicon} />} {favicon && <link rel="shortcut icon" href={baseUrl + favicon} />}
{description && <meta name="description" content={description} />}
{description && (
<meta property="og:description" content={description} />
)}
</Head> </Head>
{children} {children}
</React.Fragment> </React.Fragment>

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import React, {useContext, useEffect} from 'react'; import React, {useContext} from 'react';
import Head from '@docusaurus/Head'; import Head from '@docusaurus/Head';
import DocusaurusContext from '@docusaurus/context'; import DocusaurusContext from '@docusaurus/context';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
@ -68,14 +68,8 @@ function Home() {
const feedbackUrl = `${siteConfig.baseUrl}feedback/`; const feedbackUrl = `${siteConfig.baseUrl}feedback/`;
const gettingStartedUrl = `${siteConfig.baseUrl}docs/introduction`; const gettingStartedUrl = `${siteConfig.baseUrl}docs/introduction`;
useEffect(() => {
// Prefetch feedback pages & getting started pages
window.docusaurus.prefetch(feedbackUrl);
window.docusaurus.prefetch(gettingStartedUrl);
}, []);
return ( return (
<Layout> <Layout description={'Docusaurus makes it easy to build websites'}>
<div className={styles['index-hero']}> <div className={styles['index-hero']}>
<div className={styles['index-hero-inner']}> <div className={styles['index-hero-inner']}>
<h1 className={styles['index-hero-project-tagline']}> <h1 className={styles['index-hero-project-tagline']}>
@ -115,8 +109,8 @@ function Home() {
<a href="https://github.com/facebook/Docusaurus/issues/789"> <a href="https://github.com/facebook/Docusaurus/issues/789">
Docusaurus 2 Docusaurus 2
</a> </a>
, contribute to its roadmap by suggesting features or giving feedback{' '} , contribute to its roadmap by suggesting features or giving{' '}
<Link to={feedbackUrl}>here</Link>! <Link to={feedbackUrl}>feedback here</Link>!
</div> </div>
</div> </div>
<div className={styles.section}> <div className={styles.section}>

View file

@ -5858,13 +5858,6 @@ front-matter@^2.3.0:
dependencies: dependencies:
js-yaml "^3.10.0" js-yaml "^3.10.0"
front-matter@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-3.0.2.tgz#2401cd05fcf22bd0de48a104ffb4efb1ff5c8465"
integrity sha512-iBGZaWyzqgsrPGsqrXZP6N4hp5FzSKDi18nfAoYpgz3qK5sAwFv/ojmn3VS60SOgLvq6CtojNqy0y6ZNz05IzQ==
dependencies:
js-yaml "^3.13.1"
fs-constants@^1.0.0: fs-constants@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
@ -6330,6 +6323,16 @@ gray-matter@^2.1.0:
js-yaml "^3.8.1" js-yaml "^3.8.1"
toml "^2.3.2" toml "^2.3.2"
gray-matter@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.2.tgz#9aa379e3acaf421193fce7d2a28cebd4518ac454"
integrity sha512-7hB/+LxrOjq/dd8APlK0r24uL/67w7SkYnfwhNFwg/VDIGWGmduTDYf3WNstLW2fbbmRwrDGCVSJ2isuf2+4Hw==
dependencies:
js-yaml "^3.11.0"
kind-of "^6.0.2"
section-matter "^1.0.0"
strip-bom-string "^1.0.0"
growly@^1.3.0: growly@^1.3.0:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
@ -8095,7 +8098,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-yaml@^3.10.0, js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.8.1, js-yaml@^3.9.1: js-yaml@^3.10.0, js-yaml@^3.11.0, js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.8.1, js-yaml@^3.9.1:
version "3.13.1" version "3.13.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
@ -11991,6 +11994,14 @@ schema-utils@^1.0.0:
ajv-errors "^1.0.0" ajv-errors "^1.0.0"
ajv-keywords "^3.1.0" ajv-keywords "^3.1.0"
section-matter@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167"
integrity sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==
dependencies:
extend-shallow "^2.0.1"
kind-of "^6.0.0"
seek-bzip@^1.0.5: seek-bzip@^1.0.5:
version "1.0.5" version "1.0.5"
resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc" resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc"
@ -12737,6 +12748,11 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0:
dependencies: dependencies:
ansi-regex "^4.1.0" ansi-regex "^4.1.0"
strip-bom-string@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92"
integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=
strip-bom@^2.0.0: strip-bom@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"