mirror of
https://github.com/facebook/docusaurus.git
synced 2025-08-03 16:59:06 +02:00
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:
parent
246c1814c0
commit
305a4f0a29
21 changed files with 287 additions and 84 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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}
|
||||
`;
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -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"
|
||||
},
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
26
packages/docusaurus-theme-classic/src/theme/MDXComponents.js
Normal file
26
packages/docusaurus-theme-classic/src/theme/MDXComponents.js
Normal 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}
|
||||
/>
|
||||
),
|
||||
};
|
|
@ -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>
|
||||
);
|
||||
};
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue