feat(v2): composition syntax highlighting & live code editors (#1555)

* feat(v2): composition syntax highlighting & react-live playground

* mobile friendly tweak

* refactor styling

* revert docs
This commit is contained in:
Endi 2019-06-04 15:59:51 +07:00 committed by GitHub
parent 246c1814c0
commit 305a4f0a29
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 287 additions and 84 deletions

View file

@ -2,9 +2,6 @@
Docusaurus webpack loader of [MDX](https://github.com/mdx-js/mdx)
The extra idea here is to simplify things by adding prismjs syntax highlighting by default through https://github.com/mapbox/rehype-prism and add the prism css theme import directly (only add the CSS import if target is 'web').
## Installation
```sh
@ -18,10 +15,6 @@ yarn add @docusaurus/mdx-loader
module: {
rules: [
// ...
{
test: /\.css$/,
// Make sure your webpack loader can import css files too
},
{
test: /\.mdx?$/,
use: [
@ -40,13 +33,6 @@ module: {
## Options
### `prismTheme`
- Default: `prism-themes/themes/prism-atom-dark.css`;
This is the PrismJS theme CSS that will be imported. The supported themes are :
- prismjs/themes/XXXXXX.css (See https://github.com/PrismJS/prism/tree/master/themes)
- prism-themes/themes/XXXXXX.css (See https://github.com/PrismJS/prism-themes/tree/master/themes)
### `rehypePlugins`
Array of rehype plugins to manipulate the MDXHAST

View file

@ -10,15 +10,12 @@
"dependencies": {
"@babel/parser": "^7.4.3",
"@babel/traverse": "^7.4.3",
"@mapbox/rehype-prism": "^0.3.1",
"@mdx-js/mdx": "^1.0.18",
"@mdx-js/react": "^1.0.16",
"@mdx-js/mdx": "^1.0.20",
"@mdx-js/react": "^1.0.20",
"github-slugger": "^1.2.1",
"gray-matter": "^4.0.2",
"loader-utils": "^1.2.3",
"mdast-util-to-string": "^1.0.5",
"prism-themes": "^1.1.0",
"prismjs": "^1.16.0",
"remark-emoji": "^2.0.2",
"remark-slug": "^5.1.1",
"stringify-object": "^3.3.0",

View file

@ -7,18 +7,16 @@
const {getOptions} = require('loader-utils');
const mdx = require('@mdx-js/mdx');
const rehypePrism = require('@mapbox/rehype-prism');
const emoji = require('remark-emoji');
const slug = require('remark-slug');
const matter = require('gray-matter');
const stringifyObject = require('stringify-object');
const linkHeadings = require('./linkHeadings');
const rightToc = require('./rightToc');
const linkHeadings = require('./rehype/linkHeadings');
const rightToc = require('./remark/rightToc');
const DEFAULT_OPTIONS = {
rehypePlugins: [[rehypePrism, {ignoreMissing: true}], linkHeadings],
rehypePlugins: [linkHeadings],
remarkPlugins: [emoji, slug, rightToc],
prismTheme: 'prism-themes/themes/prism-atom-dark.css',
};
module.exports = async function(fileString) {
@ -36,7 +34,6 @@ module.exports = async function(fileString) {
...DEFAULT_OPTIONS.rehypePlugins,
...(reqOptions.rehypePlugins || []),
],
prismTheme: reqOptions.prismTheme || DEFAULT_OPTIONS.prismTheme,
filepath: this.resourcePath,
};
let result;
@ -47,16 +44,10 @@ module.exports = async function(fileString) {
return callback(err);
}
let importStr = '';
// If webpack target is web, we can import the css
if (this.target === 'web') {
importStr = `import '${options.prismTheme}';`;
}
const code = `
import React from 'react';
import { mdx } from '@mdx-js/react';
${importStr}
export const frontMatter = ${stringifyObject(data)};
${result}
`;

View file

@ -31,7 +31,6 @@ const DEFAULT_OPTIONS = {
blogTagsPostsComponent: '@theme/BlogTagsPostsPage',
remarkPlugins: [],
rehypePlugins: [],
prismTheme: '',
};
module.exports = function(context, opts) {
@ -344,7 +343,7 @@ module.exports = function(context, opts) {
},
configureWebpack(config, isServer, {getBabelLoader, getCacheLoader}) {
const {rehypePlugins, remarkPlugins, prismTheme} = options;
const {rehypePlugins, remarkPlugins} = options;
return {
module: {
rules: [
@ -359,7 +358,6 @@ module.exports = function(context, opts) {
options: {
remarkPlugins,
rehypePlugins,
prismTheme,
},
},
{

View file

@ -25,7 +25,6 @@ const DEFAULT_OPTIONS = {
docItemComponent: '@theme/DocItem',
remarkPlugins: [],
rehypePlugins: [],
prismTheme: '',
};
module.exports = function(context, opts) {
@ -161,7 +160,7 @@ module.exports = function(context, opts) {
},
configureWebpack(config, isServer, {getBabelLoader, getCacheLoader}) {
const {rehypePlugins, remarkPlugins, prismTheme} = options;
const {rehypePlugins, remarkPlugins} = options;
return {
module: {
rules: [
@ -176,7 +175,6 @@ module.exports = function(context, opts) {
options: {
remarkPlugins,
rehypePlugins,
prismTheme,
},
},
{

View file

@ -8,8 +8,12 @@
},
"license": "MIT",
"dependencies": {
"@mdx-js/mdx": "^1.0.20",
"@mdx-js/react": "^1.0.20",
"classnames": "^2.2.6",
"docsearch.js": "^2.5.2",
"prism-react-renderer": "^0.1.6",
"react-live": "^2.1.2",
"infima": "0.2.0-alpha.1",
"react-toggle": "^4.0.2"
},

View file

@ -6,11 +6,13 @@
*/
import React from 'react';
import {MDXProvider} from '@mdx-js/react';
import Head from '@docusaurus/Head';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import withBaseUrl from '@docusaurus/withBaseUrl';
import Navbar from '@theme/Navbar';
import Footer from '@theme/Footer';
import MDXComponents from '@theme/MDXComponents';
import './styles.css';
@ -30,7 +32,7 @@ function Layout(props) {
)}
</Head>
<Navbar />
{children}
<MDXProvider components={MDXComponents}>{children}</MDXProvider>
{!noFooter && <Footer />}
</React.Fragment>
);

View file

@ -0,0 +1,26 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React from 'react';
import Link from '@docusaurus/Link';
import CodeBlock from './components/CodeBlock';
export default {
code: CodeBlock,
a: Link,
pre: props => (
<pre
className="pre"
style={{
backgroundColor: 'transparent',
fontFamily: 'inherit',
padding: 0,
boxSizing: 'border-box',
}}
{...props}
/>
),
};

View file

@ -0,0 +1,54 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React from 'react';
import Highlight, {defaultProps} from 'prism-react-renderer';
import nightOwlTheme from 'prism-react-renderer/themes/nightOwl';
import Playground from '@theme/components/Playground';
export default ({children, className: languageClassName, live, ...props}) => {
if (live) {
return (
<Playground
scope={{...React}}
code={children}
theme={nightOwlTheme}
{...props}
/>
);
}
const language =
languageClassName && languageClassName.replace(/language-/, '');
return (
<Highlight
{...defaultProps}
theme={nightOwlTheme}
code={children}
language={language}>
{({className, style, tokens, getLineProps, getTokenProps}) => (
<pre
className={className}
style={{
...style,
overflow: 'hidden',
overflowWrap: 'break-word',
whiteSpace: 'pre-wrap',
fontSize: 'inherit',
}}>
{tokens.map((line, i) => (
<div key={i} {...getLineProps({line, key: i})}>
{line.map((token, key) => (
<span key={key} {...getTokenProps({token, key})} />
))}
</div>
))}
</pre>
)}
</Highlight>
);
};

View file

@ -0,0 +1,35 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import * as React from 'react';
import {LiveProvider, LiveEditor, LiveError, LivePreview} from 'react-live';
import styles from './styles.module.css';
function Playground({children, theme, transformCode, ...props}) {
return (
<LiveProvider
code={children}
transformCode={transformCode || (code => `${code};`)}
theme={theme}
{...props}>
<div className={styles.editorHeaderContainer}>
<div className={styles.headerTitle}>LIVE EDITOR</div>
</div>
<LiveEditor className={styles.editorContainer} />
<div className={styles.previewHeaderContainer}>
<div className={styles.headerTitle}>PREVIEW</div>
</div>
<div className={styles.previewContainer}>
<LivePreview />
<LiveError />
</div>
</LiveProvider>
);
}
export default Playground;

View file

@ -0,0 +1,38 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.headerTitle {
text-transform: uppercase;
color: #e1e6ef;
font-size: 11px;
font-weight: bold;
opacity: 0.4;
}
.editorHeaderContainer {
padding: 4px 8px;
background: #1a2d3c;
}
.editorContainer {
padding: 0;
border: 0;
outline: 0;
}
.previewHeaderContainer {
padding: 0 8px;
background: #1a2d3c;
height: 35px;
line-height: 34px;
}
.previewContainer {
position: relative;
padding: 16px;
border: 0.5px solid #011627;
}