feat(v2): render Markdown on server-side instead (#1077)

* feat(v2): render Markdown on server-side instead

* move to folder
This commit is contained in:
Yangshun Tay 2018-10-30 07:45:07 -07:00 committed by Endilie Yacop Sucipto
parent d479f42ff5
commit 6cec7ce982
6 changed files with 173 additions and 177 deletions

View file

@ -8,96 +8,10 @@
/* eslint-disable */
import React from 'react';
import Markdown from 'remarkable';
import Helmet from 'react-helmet';
import hljs from 'highlight.js';
import chalk from 'chalk';
import escapeHtml from 'escape-html';
import anchors from './anchors';
class MarkdownBlock extends React.Component {
content() {
if (this.props.source) {
return (
<span
dangerouslySetInnerHTML={{
__html: this.renderMarkdown(this.props.source),
}}
/>
);
}
return React.Children.map(this.props.children, child => {
if (typeof child === 'string') {
return (
<span
dangerouslySetInnerHTML={{__html: this.renderMarkdown(child)}}
/>
);
}
return child;
});
}
renderMarkdown(source) {
const alias = {
js: 'jsx',
};
const {siteConfig} = this.props;
const md = new Markdown({
langPrefix: 'hljs css language-',
highlight: function(str, rawLang) {
// Default language fallback
const defaultLang =
siteConfig.highlight && siteConfig.highlight.defaultLang;
// No syntax highlighting
if (rawLang === 'text' || (!rawLang && !defaultLang)) {
return escapeHtml(str);
}
// User's own hljs function to register additional languages
if (siteConfig.highlight && siteConfig.highlight.hljs) {
siteConfig.highlight.hljs(hljs);
}
// Syntax highlighting
const lang = rawLang.toLowerCase() || defaultLang;
try {
if (hljs.getLanguage(lang)) {
return hljs.highlight(lang, str).value;
}
} catch (e) {
console.error(
chalk.yellow(
`Highlight.js syntax highlighting for language "${lang}" is not supported.`,
),
);
}
return hljs.highlightAuto(str).value;
},
html: true,
linkify: true,
});
// Register anchors plugin
md.use(anchors);
// Allow client sites to register their own plugins
if (siteConfig.markdownPlugins) {
siteConfig.markdownPlugins.forEach(plugin => {
md.use(plugin);
});
}
const html = md.render(source);
// Ensure fenced code blocks use Highlight.js hljs class
// https://github.com/jonschlinkert/remarkable/issues/224
return html.replace(/<pre><code>/g, '<pre><code class="hljs">');
}
render() {
const {siteConfig} = this.props;
function Markdown(props) {
const {siteConfig} = props;
const highlight = Object.assign(
{},
{
@ -119,14 +33,13 @@ class MarkdownBlock extends React.Component {
<Helmet>
<link rel="stylesheet" type="text/css" href={highlightThemeURL} />
</Helmet>
{this.content()}
<div>{props.children}</div>
</div>
);
}
}
MarkdownBlock.defaultProps = {
Markdown.defaultProps = {
siteConfig: {},
};
export default MarkdownBlock;
export default Markdown;

View file

@ -7,10 +7,10 @@
input#search_input_react {
align-self: center;
background-color: #c6cbd1;
background-color: #f2f3f5;
border: none;
border-radius: 20px;
color: #fff;
color: #000;
font-size: 14px;
font-weight: 300;
line-height: 20px;
@ -44,26 +44,27 @@ input::placeholder {
/* Bottom border of each suggestion */
.algolia-docsearch-suggestion {
border-bottom-color: #3A3DD1;
border-bottom-color: #3a3dd1;
}
/* Main category headers */
.algolia-docsearch-suggestion--category-header {
background-color: #4B54DE;
background-color: #4b54de;
}
/* Highlighted search terms */
.algolia-docsearch-suggestion--highlight {
color: #3A33D1;
color: #3a33d1;
}
/* Highligted search terms in the main category headers */
.algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--highlight {
background-color: #4D47D5;
.algolia-docsearch-suggestion--category-header
.algolia-docsearch-suggestion--highlight {
background-color: #4d47d5;
}
/* Currently selected suggestion */
.aa-cursor .algolia-docsearch-suggestion--content {
color: #272296;
}
.aa-cursor .algolia-docsearch-suggestion {
background: #EBEBFB;
background: #ebebfb;
}
/* For bigger screens, when displaying results in two columns */
@ -75,8 +76,8 @@ input::placeholder {
/* Left column, with secondary category header */
.algolia-docsearch-suggestion--subcategory-column {
border-right-color: #7671df;
background-color: #F2F2FF;
color: #4E4726;
background-color: #f2f2ff;
color: #4e4726;
}
}
@ -106,12 +107,12 @@ input::placeholder {
.searchbox__input {
display: inline-block;
box-sizing: border-box;
-webkit-transition: box-shadow .4s ease, background .4s ease;
transition: box-shadow .4s ease, background .4s ease;
-webkit-transition: box-shadow 0.4s ease, background 0.4s ease;
transition: box-shadow 0.4s ease, background 0.4s ease;
border: 0;
border-radius: 16px;
box-shadow: inset 0 0 0 1px #CCCCCC;
background: #FFFFFF !important;
box-shadow: inset 0 0 0 1px #cccccc;
background: #ffffff !important;
padding: 0;
padding-right: 26px;
padding-left: 32px;
@ -125,7 +126,10 @@ input::placeholder {
appearance: none;
}
.searchbox__input::-webkit-search-decoration, .searchbox__input::-webkit-search-cancel-button, .searchbox__input::-webkit-search-results-button, .searchbox__input::-webkit-search-results-decoration {
.searchbox__input::-webkit-search-decoration,
.searchbox__input::-webkit-search-cancel-button,
.searchbox__input::-webkit-search-results-button,
.searchbox__input::-webkit-search-results-decoration {
display: none;
}
@ -133,26 +137,27 @@ input::placeholder {
box-shadow: inset 0 0 0 1px #b3b3b3;
}
.searchbox__input:focus, .searchbox__input:active {
.searchbox__input:focus,
.searchbox__input:active {
outline: 0;
box-shadow: inset 0 0 0 1px #AAAAAA;
background: #FFFFFF;
box-shadow: inset 0 0 0 1px #aaaaaa;
background: #ffffff;
}
.searchbox__input::-webkit-input-placeholder {
color: #AAAAAA;
color: #aaaaaa;
}
.searchbox__input::-moz-placeholder {
color: #AAAAAA;
color: #aaaaaa;
}
.searchbox__input:-ms-input-placeholder {
color: #AAAAAA;
color: #aaaaaa;
}
.searchbox__input::placeholder {
color: #AAAAAA;
color: #aaaaaa;
}
.searchbox__submit {
@ -184,7 +189,8 @@ input::placeholder {
content: '';
}
.searchbox__submit:hover, .searchbox__submit:active {
.searchbox__submit:hover,
.searchbox__submit:active {
cursor: pointer;
}
@ -196,7 +202,7 @@ input::placeholder {
width: 14px;
height: 14px;
vertical-align: middle;
fill: #6D7E96;
fill: #6d7e96;
}
.searchbox__reset {
@ -236,8 +242,8 @@ input::placeholder {
display: block;
-webkit-animation-name: sbx-reset-in;
animation-name: sbx-reset-in;
-webkit-animation-duration: .15s;
animation-duration: .15s;
-webkit-animation-duration: 0.15s;
animation-duration: 0.15s;
}
@-webkit-keyframes sbx-reset-in {
@ -266,7 +272,6 @@ input::placeholder {
}
}
.algolia-autocomplete .ds-dropdown-menu:before {
display: block;
position: absolute;
@ -341,7 +346,7 @@ input::placeholder {
cursor: pointer;
}
.algolia-autocomplete .ds-dropdown-menu [class^="ds-dataset-"] {
.algolia-autocomplete .ds-dropdown-menu [class^='ds-dataset-'] {
position: relative;
border-radius: 4px;
overflow: auto;
@ -368,13 +373,21 @@ input::placeholder {
padding: 0.1em 0.05em;
}
.algolia-autocomplete .algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--category-header-lvl0 .algolia-docsearch-suggestion--highlight,
.algolia-autocomplete .algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--category-header-lvl1 .algolia-docsearch-suggestion--highlight {
.algolia-autocomplete
.algolia-docsearch-suggestion--category-header
.algolia-docsearch-suggestion--category-header-lvl0
.algolia-docsearch-suggestion--highlight,
.algolia-autocomplete
.algolia-docsearch-suggestion--category-header
.algolia-docsearch-suggestion--category-header-lvl1
.algolia-docsearch-suggestion--highlight {
color: inherit;
background: inherit;
}
.algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight {
.algolia-autocomplete
.algolia-docsearch-suggestion--text
.algolia-docsearch-suggestion--highlight {
padding: 0 0 1px;
background: inherit;
box-shadow: inset 0 -2px 0 0 rgba(69, 142, 225, 0.8);
@ -445,7 +458,9 @@ input::placeholder {
right: 0;
}
.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column .algolia-docsearch-suggestion--highlight {
.algolia-autocomplete
.algolia-docsearch-suggestion--subcategory-column
.algolia-docsearch-suggestion--highlight {
background-color: inherit;
color: inherit;
}
@ -456,7 +471,7 @@ input::placeholder {
.algolia-autocomplete .algolia-docsearch-suggestion--title {
margin-bottom: 4px;
color: #02060C;
color: #02060c;
font-size: 0.9em;
font-weight: bold;
}
@ -465,7 +480,7 @@ input::placeholder {
display: block;
line-height: 1.2em;
font-size: 0.85em;
color: #63676D;
color: #63676d;
padding-right: 2px;
}
@ -478,7 +493,9 @@ input::placeholder {
margin-top: -8px;
}
.algolia-autocomplete .algolia-docsearch-suggestion--no-results .algolia-docsearch-suggestion--text {
.algolia-autocomplete
.algolia-docsearch-suggestion--no-results
.algolia-docsearch-suggestion--text {
color: #ffffff;
margin-top: 4px;
}
@ -492,24 +509,31 @@ input::placeholder {
font-size: 90%;
border: none;
color: #222222;
background-color: #EBEBEB;
background-color: #ebebeb;
border-radius: 3px;
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
.algolia-autocomplete .algolia-docsearch-suggestion code .algolia-docsearch-suggestion--highlight {
.algolia-autocomplete
.algolia-docsearch-suggestion
code
.algolia-docsearch-suggestion--highlight {
background: none;
}
.algolia-autocomplete .algolia-docsearch-suggestion.algolia-docsearch-suggestion__main .algolia-docsearch-suggestion--category-header {
.algolia-autocomplete
.algolia-docsearch-suggestion.algolia-docsearch-suggestion__main
.algolia-docsearch-suggestion--category-header {
display: block;
}
.algolia-autocomplete .algolia-docsearch-suggestion.algolia-docsearch-suggestion__secondary .algolia-docsearch-suggestion--subcategory-column {
.algolia-autocomplete
.algolia-docsearch-suggestion.algolia-docsearch-suggestion__secondary
.algolia-docsearch-suggestion--subcategory-column {
display: block;
}
.algolia-autocomplete .algolia-docsearch-footer {
background-color: #fff;
width: 100%;

View file

@ -10,7 +10,7 @@ const CSSExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const path = require('path');
const mdLoader = require.resolve('./loader/markdown');
const mdLoader = require.resolve('./loaders/markdown');
const CSS_REGEX = /\.css$/;
const CSS_MODULE_REGEX = /\.module\.css$/;

View file

@ -5,9 +5,9 @@
* LICENSE file in the root directory of this source tree.
*/
import toSlug from './toSlug';
const toSlug = require('./toSlug');
export default function anchors(md) {
function anchors(md) {
const originalRender = md.renderer.rules.heading_close;
// eslint-disable-next-line
@ -26,3 +26,5 @@ export default function anchors(md) {
return originalRender(tokens, idx, options, env);
};
}
module.exports = anchors;

View file

@ -5,9 +5,15 @@
* LICENSE file in the root directory of this source tree.
*/
const fm = require('front-matter');
const {getOptions} = require('loader-utils');
const path = require('path');
const fm = require('front-matter');
const Remarkable = require('remarkable');
const hljs = require('highlight.js');
const chalk = require('chalk');
const escapeHtml = require('escape-html');
const anchors = require('./anchors');
module.exports = function(fileString) {
const options = getOptions(this);
@ -88,13 +94,64 @@ module.exports = function(fileString) {
content = lines.join('\n');
}
const md = new Remarkable({
langPrefix: 'hljs css language-',
highlight(str, rawLang) {
// Default language fallback
const defaultLang =
siteConfig.highlight && siteConfig.highlight.defaultLang;
// No syntax highlighting
if (rawLang === 'text' || (!rawLang && !defaultLang)) {
return escapeHtml(str);
}
// User's own hljs function to register additional languages
if (siteConfig.highlight && siteConfig.highlight.hljs) {
siteConfig.highlight.hljs(hljs);
}
// Syntax highlighting
const lang = rawLang.toLowerCase() || defaultLang;
try {
if (hljs.getLanguage(lang)) {
return hljs.highlight(lang, str).value;
}
} catch (e) {
console.error(
chalk.yellow(
`Highlight.js syntax highlighting for language "${lang}" is not supported.`,
),
);
}
return hljs.highlightAuto(str).value;
},
html: true,
linkify: true,
});
// Register anchors plugin
md.use(anchors);
// Allow client sites to register their own plugins
if (siteConfig.markdownPlugins) {
siteConfig.markdownPlugins.forEach(plugin => {
md.use(plugin);
});
}
// Ensure fenced code blocks use Highlight.js hljs class
// https://github.com/jonschlinkert/remarkable/issues/224
const html = md
.render(content)
.replace(/<pre><code>/g, '<pre><code class="hljs">');
/* Return a React component */
return `
import React from 'react';
import Markdown from '@theme/Markdown';
export default () => (
<Markdown siteConfig={${JSON.stringify(siteConfig)}}>
{${JSON.stringify(content)}}
<div dangerouslySetInnerHTML={{__html: ${JSON.stringify(html)}}} />
</Markdown>
);`;
};