mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 15:47:23 +02:00
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:
parent
34195e4c30
commit
6136fbe1d2
21 changed files with 82 additions and 58 deletions
|
@ -10,9 +10,9 @@
|
|||
"dependencies": {
|
||||
"@docusaurus/mdx-loader": "^2.0.0-alpha.13",
|
||||
"@docusaurus/utils": "^2.0.0-alpha.13",
|
||||
"front-matter": "^3.0.1",
|
||||
"fs-extra": "^7.0.1",
|
||||
"globby": "^9.1.0",
|
||||
"gray-matter": "^4.0.2",
|
||||
"loader-utils": "^1.2.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
|
|
@ -75,7 +75,7 @@ class DocusaurusPluginContentBlog {
|
|||
);
|
||||
|
||||
const fileString = await fs.readFile(source, 'utf-8');
|
||||
const {metadata: rawMetadata} = parse(fileString);
|
||||
const {metadata: rawMetadata, excerpt: description} = parse(fileString);
|
||||
|
||||
const metadata = {
|
||||
permalink: normalizeUrl([
|
||||
|
@ -84,6 +84,7 @@ class DocusaurusPluginContentBlog {
|
|||
fileToUrl(blogFileName),
|
||||
]),
|
||||
source,
|
||||
description,
|
||||
...rawMetadata,
|
||||
date,
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 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 TRUNCATE_MARKER = /<!--\s*truncate\s*-->/;
|
||||
|
@ -14,7 +14,7 @@ module.exports = async function(fileString) {
|
|||
const callback = this.async();
|
||||
|
||||
// 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)
|
||||
const {truncated} = this.resourceQuery && parseQuery(this.resourceQuery);
|
||||
|
|
|
@ -17,7 +17,7 @@ function BlogListPage(props) {
|
|||
} = props;
|
||||
|
||||
return (
|
||||
<Layout title="Blog">
|
||||
<Layout title="Blog" description="Blog">
|
||||
<div className="container margin-vert--xl">
|
||||
<div className="row">
|
||||
<div className="col col--6 col--offset-3">
|
||||
|
|
|
@ -14,7 +14,7 @@ function BlogPostPage(props) {
|
|||
const {content: BlogPostContents, metadata} = props;
|
||||
|
||||
return (
|
||||
<Layout title={metadata.title}>
|
||||
<Layout title={metadata.title} description={metadata.description}>
|
||||
{BlogPostContents && (
|
||||
<div className="container margin-vert--xl">
|
||||
<div className="row">
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
"@babel/polyfill": "^7.4.0",
|
||||
"@docusaurus/mdx-loader": "^2.0.0-alpha.13",
|
||||
"@docusaurus/utils": "^2.0.0-alpha.13",
|
||||
"front-matter": "^3.0.1",
|
||||
"fs-extra": "^7.0.1",
|
||||
"globby": "^9.1.0",
|
||||
"gray-matter": "^4.0.2",
|
||||
"import-fresh": "^3.0.0",
|
||||
"loader-utils": "^1.2.3"
|
||||
},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
id: bar
|
||||
title: Bar
|
||||
description: This is custom description
|
||||
---
|
||||
|
||||
# Remarkable
|
||||
|
|
|
@ -39,6 +39,7 @@ describe('loadDocs', () => {
|
|||
sidebar: 'docs',
|
||||
source: path.join(docsDir, 'hello.md'),
|
||||
title: 'Hello, World !',
|
||||
description: `Hi, Endilie here :)`,
|
||||
});
|
||||
expect(docsMetadata['foo/bar']).toEqual({
|
||||
category: 'Test',
|
||||
|
@ -49,6 +50,7 @@ describe('loadDocs', () => {
|
|||
sidebar: 'docs',
|
||||
source: path.join(docsDir, 'foo', 'bar.md'),
|
||||
title: 'Bar',
|
||||
description: 'This is custom description',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -40,12 +40,14 @@ describe('processMetadata', () => {
|
|||
permalink: '/docs/foo/bar',
|
||||
source: path.join(docsDir, sourceA),
|
||||
title: 'Bar',
|
||||
description: 'This is custom description',
|
||||
});
|
||||
expect(dataB).toEqual({
|
||||
id: 'hello',
|
||||
permalink: '/docs/hello',
|
||||
source: path.join(docsDir, sourceB),
|
||||
title: 'Hello, World !',
|
||||
description: `Hi, Endilie here :)`,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -57,6 +59,7 @@ describe('processMetadata', () => {
|
|||
permalink: '/docs/endiliey/permalink',
|
||||
source: path.join(docsDir, source),
|
||||
title: 'Permalink',
|
||||
description: 'This has a different permalink',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 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 {resolve} = require('url');
|
||||
|
||||
|
@ -17,7 +17,7 @@ module.exports = async function(fileString) {
|
|||
const {docsDir, sourceToPermalink} = options;
|
||||
|
||||
// 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
|
||||
let sourceDir;
|
||||
|
@ -27,10 +27,9 @@ module.exports = async function(fileString) {
|
|||
}
|
||||
|
||||
// Replace internal markdown linking (except in fenced blocks).
|
||||
let content = body;
|
||||
if (sourceDir) {
|
||||
let fencedBlock = false;
|
||||
const lines = body.split('\n').map(line => {
|
||||
const lines = content.split('\n').map(line => {
|
||||
if (line.trim().startsWith('```')) {
|
||||
fencedBlock = !fencedBlock;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ module.exports = async function processMetadata(
|
|||
) {
|
||||
const filepath = path.resolve(refDir, source);
|
||||
const fileString = await fs.readFile(filepath, 'utf-8');
|
||||
const {metadata} = parse(fileString);
|
||||
const {metadata = {}, excerpt} = parse(fileString);
|
||||
|
||||
// Default id is the file name.
|
||||
if (!metadata.id) {
|
||||
|
@ -33,6 +33,10 @@ module.exports = async function processMetadata(
|
|||
metadata.title = metadata.id;
|
||||
}
|
||||
|
||||
if (!metadata.description) {
|
||||
metadata.description = excerpt;
|
||||
}
|
||||
|
||||
const dirName = path.dirname(source);
|
||||
if (dirName !== '.') {
|
||||
const prefix = dirName;
|
||||
|
|
|
@ -14,13 +14,19 @@ import DocSidebar from '@theme/DocSidebar';
|
|||
|
||||
function DocPage(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 (
|
||||
<Layout noFooter>
|
||||
<Layout noFooter description={description}>
|
||||
<div className="container container--fluid">
|
||||
<div className="row">
|
||||
<div className="col col--3">
|
||||
<DocSidebar docsMetadata={docsMetadata} location={location} />
|
||||
<DocSidebar docsMetadata={docsMetadata} sidebar={sidebar} />
|
||||
</div>
|
||||
<div className="col col--9">
|
||||
{renderRoutes(route.routes, {docsMetadata})}
|
||||
|
|
|
@ -12,13 +12,7 @@ import Link from '@docusaurus/Link'; // eslint-disable-line
|
|||
import './styles.css';
|
||||
|
||||
function DocSidebar(props) {
|
||||
const {docsMetadata, location} = props;
|
||||
|
||||
const id =
|
||||
docsMetadata.permalinkToId[location.pathname] ||
|
||||
docsMetadata.permalinkToId[location.pathname.replace(/\/$/, '')];
|
||||
const metadata = docsMetadata.docs[id] || {};
|
||||
const {sidebar} = metadata;
|
||||
const {docsMetadata, sidebar} = props;
|
||||
|
||||
if (!sidebar) {
|
||||
return null;
|
||||
|
|
|
@ -17,12 +17,16 @@ function Layout(props) {
|
|||
const context = useDocusaurusContext();
|
||||
const {siteConfig = {}} = context;
|
||||
const {baseUrl, favicon, tagline, title: defaultTitle} = siteConfig;
|
||||
const {children, title, noFooter} = props;
|
||||
const {children, title, noFooter, description} = props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Head defaultTitle={`${defaultTitle} · ${tagline}`}>
|
||||
{title && <title>{`${title} · ${tagline}`}</title>}
|
||||
{favicon && <link rel="shortcut icon" href={baseUrl + favicon} />}
|
||||
{description && <meta name="description" content={description} />}
|
||||
{description && (
|
||||
<meta property="og:description" content={description} />
|
||||
)}
|
||||
</Head>
|
||||
<Navbar />
|
||||
{children}
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"front-matter": "^3.0.1",
|
||||
"fs-extra": "^7.0.0",
|
||||
"gray-matter": "^4.0.2",
|
||||
"lodash": "^4.17.11"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
const path = require('path');
|
||||
const fm = require('front-matter');
|
||||
const matter = require('gray-matter');
|
||||
const {createHash} = require('crypto');
|
||||
|
||||
const _ = require(`lodash`);
|
||||
|
@ -163,15 +163,19 @@ function getSubFolder(file, refDir) {
|
|||
|
||||
/**
|
||||
* @param {string} fileString
|
||||
* @returns {*}
|
||||
* @returns {Object}
|
||||
*/
|
||||
function parse(fileString) {
|
||||
if (!fm.test(fileString)) {
|
||||
return {metadata: null, content: fileString};
|
||||
}
|
||||
const {attributes: metadata, body: content} = fm(fileString);
|
||||
|
||||
return {metadata, content};
|
||||
const {data: metadata, content, excerpt} = matter(fileString, {
|
||||
excerpt(file) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
file.excerpt = file.content
|
||||
.trim()
|
||||
.split('\n', 1)
|
||||
.shift();
|
||||
},
|
||||
});
|
||||
return {metadata, content, excerpt};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
"ejs": "^2.6.1",
|
||||
"envinfo": "^7.2.0",
|
||||
"express": "^4.16.4",
|
||||
"front-matter": "^3.0.1",
|
||||
"fs-extra": "^7.0.0",
|
||||
"globby": "^9.1.0",
|
||||
"html-webpack-plugin": "^4.0.0-beta.5",
|
||||
|
|
|
@ -19,13 +19,6 @@ function App() {
|
|||
<DocusaurusContext.Provider value={{siteConfig}}>
|
||||
{/* TODO: this link stylesheet to infima is temporary */}
|
||||
<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
|
||||
href="https://infima-dev.netlify.com/css/default/default.min.css"
|
||||
preload
|
||||
|
|
|
@ -13,12 +13,16 @@ function Layout(props) {
|
|||
const context = useDocusaurusContext();
|
||||
const {siteConfig = {}} = context;
|
||||
const {baseUrl, favicon, tagline, title: defaultTitle} = siteConfig;
|
||||
const {children, title} = props;
|
||||
const {children, title, description} = props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Head defaultTitle={`${defaultTitle} · ${tagline}`}>
|
||||
{title && <title>{`${title} · ${tagline}`}</title>}
|
||||
{favicon && <link rel="shortcut icon" href={baseUrl + favicon} />}
|
||||
{description && <meta name="description" content={description} />}
|
||||
{description && (
|
||||
<meta property="og:description" content={description} />
|
||||
)}
|
||||
</Head>
|
||||
{children}
|
||||
</React.Fragment>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 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 DocusaurusContext from '@docusaurus/context';
|
||||
import Link from '@docusaurus/Link';
|
||||
|
@ -68,14 +68,8 @@ function Home() {
|
|||
const feedbackUrl = `${siteConfig.baseUrl}feedback/`;
|
||||
const gettingStartedUrl = `${siteConfig.baseUrl}docs/introduction`;
|
||||
|
||||
useEffect(() => {
|
||||
// Prefetch feedback pages & getting started pages
|
||||
window.docusaurus.prefetch(feedbackUrl);
|
||||
window.docusaurus.prefetch(gettingStartedUrl);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Layout description={'Docusaurus makes it easy to build websites'}>
|
||||
<div className={styles['index-hero']}>
|
||||
<div className={styles['index-hero-inner']}>
|
||||
<h1 className={styles['index-hero-project-tagline']}>
|
||||
|
@ -115,8 +109,8 @@ function Home() {
|
|||
<a href="https://github.com/facebook/Docusaurus/issues/789">
|
||||
Docusaurus 2
|
||||
</a>
|
||||
, contribute to its roadmap by suggesting features or giving feedback{' '}
|
||||
<Link to={feedbackUrl}>here</Link>!
|
||||
, contribute to its roadmap by suggesting features or giving{' '}
|
||||
<Link to={feedbackUrl}>feedback here</Link>!
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.section}>
|
||||
|
|
32
yarn.lock
32
yarn.lock
|
@ -5858,13 +5858,6 @@ front-matter@^2.3.0:
|
|||
dependencies:
|
||||
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:
|
||||
version "1.0.0"
|
||||
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"
|
||||
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:
|
||||
version "1.3.0"
|
||||
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"
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
|
||||
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
|
||||
|
@ -11991,6 +11994,14 @@ schema-utils@^1.0.0:
|
|||
ajv-errors "^1.0.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:
|
||||
version "1.0.5"
|
||||
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:
|
||||
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:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue