Skip to content

Commit

Permalink
Add experimental react support within markdown
Browse files Browse the repository at this point in the history
Also added fronmatter for interactive: true to turn on React on a file by file
basis and prevent slowing down the builds for non-react files
  • Loading branch information
chiedo committed Oct 17, 2020
1 parent 0547215 commit 71ffb35
Show file tree
Hide file tree
Showing 13 changed files with 32,457 additions and 545 deletions.
25,147 changes: 25,147 additions & 0 deletions assets/js/react-dom.development.js

Large diffs are not rendered by default.

3,318 changes: 3,318 additions & 0 deletions assets/js/react.development.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ intro: 'While you can grant read/write access to collaborators on a personal rep
versions:
free-pro-team: '*'
enterprise-server: '*'
interactive: true
---

### Personal user accounts
Expand All @@ -17,16 +18,31 @@ A repository owned by a user account has two permission levels: the *repository

### Organization accounts

<!--react-->
<BlueContent>

Hello world!

</BlueContent>
<!--end-react-->

Organization members can have *owner*{% if currentVersion == "free-pro-team@latest" %}, *billing manager*,{% endif %} or *member* roles. Owners have complete administrative access to your organization{% if currentVersion == "free-pro-team@latest" %}, while billing managers can manage billing settings{% endif %}. Member is the default role for everyone else. You can manage access permissions for multiple members at a time with teams. For more information, see:
- "[Permission levels for an organization](/articles/permission-levels-for-an-organization)"
- "[Project board permissions for an organization](/articles/project-board-permissions-for-an-organization)"
- "[Repository permission levels for an organization](/articles/repository-permission-levels-for-an-organization)"
- "[About teams](/articles/about-teams)"

<!--react--><BlueContent>More blue content!</BlueContent><!--end-react-->

<!--react--><RedContent>Red content!</RedContent><!--end-react-->

<!--react--><Timer /><!--end-react-->

{% if currentVersion == "free-pro-team@latest" %}

### Enterprise accounts


*Enterprise owners* have ultimate power over the enterprise account and can take every action in the enterprise account. *Billing managers* can manage your enterprise account's billing settings. Members and outside collaborators of organizations owned by your enterprise account are automatically members of the enterprise account, although they have no access to the enterprise account itself or its settings. For more information, see "[Roles for an enterprise account](/articles/roles-for-an-enterprise-account)."

{% data reusables.gated-features.enterprise-accounts %}
Expand Down
2 changes: 2 additions & 0 deletions includes/head.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@
<link rel="stylesheet" href="/dist/index.css">
<link rel="alternate icon" type="image/png" href="/assets/images/site/favicon.png">
<link rel="icon" type="image/svg+xml" href="/assets/images/site/favicon.svg">
<script src="/assets/js/react.development.js" crossorigin></script>
<script src="/assets/js/react-dom.development.js" crossorigin></script>
</head>
3 changes: 3 additions & 0 deletions lib/frontmatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ const schema = {
quickstart: { type: 'string' },
learn: { type: 'string' }
}
},
interactive: {
type: 'boolean'
}
}
}
Expand Down
25 changes: 24 additions & 1 deletion lib/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ const pathUtils = require('./path-utils')
const Permalink = require('./permalink')
const languages = require('./languages')
const renderContent = require('./render-content')
const renderReact = require('./react-engine')
const frontmatter = require('./frontmatter')
const products = require('./all-products')
const slash = require('slash')


class Page {
constructor (opts) {
assert(opts.relativePath, 'relativePath is required')
Expand Down Expand Up @@ -119,9 +121,30 @@ class Page {
this.title = await renderContent(this.rawTitle, context, { textOnly: true, encodeEntities: true })
this.shortTitle = await renderContent(this.shortTitle, context, { textOnly: true, encodeEntities: true })

const markdown = this.mapTopic
let markdown = this.mapTopic
? getMapTopicContent(this, context.pages, context.redirects)
: this.markdown

// If the article is interactive parse the React!
if (this.interactive) {
// Search for the react code comments to find the react components
const reactComponents = markdown.match(/<!--react-->(.*?)<!--end-react-->/gms)

// Render each of the react components in the Markdown
for (const index in reactComponents) {
let componentStr = reactComponents[index]

// Remove the React comment indicators
componentStr = componentStr.replace('<!--react-->\n', '').replace('<!--react-->', '')
componentStr = componentStr.replace('\n<!--end-react-->', '').replace('<!--end-react-->', '')

// Get the rendered component
const renderedComponent = await renderReact(componentStr)

// Replace the react component with the rendered html
markdown = markdown.replace(reactComponents[index], renderedComponent)
}
}

const html = await renderContent(markdown, context)

Expand Down
49 changes: 49 additions & 0 deletions lib/react-engine.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const babel = require('@babel/core')
const React = require('react')
const { renderToString } = require('react-dom/server')
const mdx = require('@mdx-js/mdx')
const { MDXProvider, mdx: createElement } = require('@mdx-js/react')
const BlueContent = require('../dist/react/BlueContent')
const RedContent = require('../dist/react/RedContent')
const Timer = require('../dist/react/Timer')

const transform = code =>
babel.transform(code, {
plugins: [
'@babel/plugin-transform-react-jsx',
'@babel/plugin-proposal-object-rest-spread'
]
}).code

const renderReact = async componentStr => {
const jsx = await mdx(componentStr, { skipExport: true })
const component = transform(jsx)
const scope = { mdx: createElement }

/* eslint-disable-next-line */
const fn = new Function(
'React',
...Object.keys(scope),
`${component}; return React.createElement(MDXContent)`
)

const element = fn(React, ...Object.values(scope))

// All components that we want accessible to markdown files must
// be registered here
const components = {
BlueContent,
RedContent,
Timer
}

const elementWithProvider = React.createElement(
MDXProvider,
{ components },
element
)

return renderToString(elementWithProvider)
}

module.exports = renderReact
Loading

0 comments on commit 71ffb35

Please sign in to comment.