Skip to content

Commit 71ffb35

Browse files
committed
Add experimental react support within markdown
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
1 parent 0547215 commit 71ffb35

File tree

13 files changed

+32457
-545
lines changed

13 files changed

+32457
-545
lines changed

assets/js/react-dom.development.js

Lines changed: 25147 additions & 0 deletions
Large diffs are not rendered by default.

assets/js/react.development.js

Lines changed: 3318 additions & 0 deletions
Large diffs are not rendered by default.

content/github/getting-started-with-github/access-permissions-on-github.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ intro: 'While you can grant read/write access to collaborators on a personal rep
99
versions:
1010
free-pro-team: '*'
1111
enterprise-server: '*'
12+
interactive: true
1213
---
1314

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

1819
### Organization accounts
1920

21+
<!--react-->
22+
<BlueContent>
23+
24+
Hello world!
25+
26+
</BlueContent>
27+
<!--end-react-->
28+
2029
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:
2130
- "[Permission levels for an organization](/articles/permission-levels-for-an-organization)"
2231
- "[Project board permissions for an organization](/articles/project-board-permissions-for-an-organization)"
2332
- "[Repository permission levels for an organization](/articles/repository-permission-levels-for-an-organization)"
2433
- "[About teams](/articles/about-teams)"
2534

35+
<!--react--><BlueContent>More blue content!</BlueContent><!--end-react-->
36+
37+
<!--react--><RedContent>Red content!</RedContent><!--end-react-->
38+
39+
<!--react--><Timer /><!--end-react-->
40+
2641
{% if currentVersion == "free-pro-team@latest" %}
2742

2843
### Enterprise accounts
2944

45+
3046
*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)."
3147

3248
{% data reusables.gated-features.enterprise-accounts %}

includes/head.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,6 @@
2626
<link rel="stylesheet" href="/dist/index.css">
2727
<link rel="alternate icon" type="image/png" href="/assets/images/site/favicon.png">
2828
<link rel="icon" type="image/svg+xml" href="/assets/images/site/favicon.svg">
29+
<script src="/assets/js/react.development.js" crossorigin></script>
30+
<script src="/assets/js/react-dom.development.js" crossorigin></script>
2931
</head>

lib/frontmatter.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ const schema = {
7070
quickstart: { type: 'string' },
7171
learn: { type: 'string' }
7272
}
73+
},
74+
interactive: {
75+
type: 'boolean'
7376
}
7477
}
7578
}

lib/page.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ const pathUtils = require('./path-utils')
1515
const Permalink = require('./permalink')
1616
const languages = require('./languages')
1717
const renderContent = require('./render-content')
18+
const renderReact = require('./react-engine')
1819
const frontmatter = require('./frontmatter')
1920
const products = require('./all-products')
2021
const slash = require('slash')
2122

23+
2224
class Page {
2325
constructor (opts) {
2426
assert(opts.relativePath, 'relativePath is required')
@@ -119,9 +121,30 @@ class Page {
119121
this.title = await renderContent(this.rawTitle, context, { textOnly: true, encodeEntities: true })
120122
this.shortTitle = await renderContent(this.shortTitle, context, { textOnly: true, encodeEntities: true })
121123

122-
const markdown = this.mapTopic
124+
let markdown = this.mapTopic
123125
? getMapTopicContent(this, context.pages, context.redirects)
124126
: this.markdown
127+
128+
// If the article is interactive parse the React!
129+
if (this.interactive) {
130+
// Search for the react code comments to find the react components
131+
const reactComponents = markdown.match(/<!--react-->(.*?)<!--end-react-->/gms)
132+
133+
// Render each of the react components in the Markdown
134+
for (const index in reactComponents) {
135+
let componentStr = reactComponents[index]
136+
137+
// Remove the React comment indicators
138+
componentStr = componentStr.replace('<!--react-->\n', '').replace('<!--react-->', '')
139+
componentStr = componentStr.replace('\n<!--end-react-->', '').replace('<!--end-react-->', '')
140+
141+
// Get the rendered component
142+
const renderedComponent = await renderReact(componentStr)
143+
144+
// Replace the react component with the rendered html
145+
markdown = markdown.replace(reactComponents[index], renderedComponent)
146+
}
147+
}
125148

126149
const html = await renderContent(markdown, context)
127150

lib/react-engine.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
const babel = require('@babel/core')
2+
const React = require('react')
3+
const { renderToString } = require('react-dom/server')
4+
const mdx = require('@mdx-js/mdx')
5+
const { MDXProvider, mdx: createElement } = require('@mdx-js/react')
6+
const BlueContent = require('../dist/react/BlueContent')
7+
const RedContent = require('../dist/react/RedContent')
8+
const Timer = require('../dist/react/Timer')
9+
10+
const transform = code =>
11+
babel.transform(code, {
12+
plugins: [
13+
'@babel/plugin-transform-react-jsx',
14+
'@babel/plugin-proposal-object-rest-spread'
15+
]
16+
}).code
17+
18+
const renderReact = async componentStr => {
19+
const jsx = await mdx(componentStr, { skipExport: true })
20+
const component = transform(jsx)
21+
const scope = { mdx: createElement }
22+
23+
/* eslint-disable-next-line */
24+
const fn = new Function(
25+
'React',
26+
...Object.keys(scope),
27+
`${component}; return React.createElement(MDXContent)`
28+
)
29+
30+
const element = fn(React, ...Object.values(scope))
31+
32+
// All components that we want accessible to markdown files must
33+
// be registered here
34+
const components = {
35+
BlueContent,
36+
RedContent,
37+
Timer
38+
}
39+
40+
const elementWithProvider = React.createElement(
41+
MDXProvider,
42+
{ components },
43+
element
44+
)
45+
46+
return renderToString(elementWithProvider)
47+
}
48+
49+
module.exports = renderReact

0 commit comments

Comments
 (0)