From d255c1afc6603202fcee12daa586d7376fc8d7e0 Mon Sep 17 00:00:00 2001 From: Eric Simons Date: Sun, 15 Oct 2017 11:36:37 -0700 Subject: [PATCH 1/9] sync js files to codepen --- .eslintignore | 5 ++- content/docs/hello-world.md | 2 +- content/docs/introducing-jsx.md | 2 +- examples/hello-world.js | 4 ++ examples/index.html | 3 ++ examples/introducing-jsx.js | 19 ++++++++++ gatsby-node.js | 42 ++++++++++++++++----- package.json | 2 +- src/templates/codepen-example.js | 64 ++++++++++++++++++++++++++++++++ 9 files changed, 130 insertions(+), 13 deletions(-) create mode 100644 examples/hello-world.js create mode 100644 examples/index.html create mode 100644 examples/introducing-jsx.js create mode 100644 src/templates/codepen-example.js diff --git a/.eslintignore b/.eslintignore index ff8a5577..94254171 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,4 +4,7 @@ node_modules/* content/* # Ignore built files -public/* \ No newline at end of file +public/* + +# Ignore examples +examples/* \ No newline at end of file diff --git a/content/docs/hello-world.md b/content/docs/hello-world.md index f9be3bde..06087d7b 100644 --- a/content/docs/hello-world.md +++ b/content/docs/hello-world.md @@ -11,7 +11,7 @@ redirect_from: - "docs/getting-started-zh-CN.html" --- -The easiest way to get started with React is to use [this Hello World example code on CodePen](http://codepen.io/gaearon/pen/ZpvBNJ?editors=0010). You don't need to install anything; you can just open it in another tab and follow along as we go through examples. If you'd rather use a local development environment, check out the [Installation](/docs/installation.html) page. +The easiest way to get started with React is to use this Hello World example code on CodePen. You don't need to install anything; you can just open it in another tab and follow along as we go through examples. If you'd rather use a local development environment, check out the [Installation](/docs/installation.html) page. The smallest React example looks like this: diff --git a/content/docs/introducing-jsx.md b/content/docs/introducing-jsx.md index 9830ddc9..e1e4d64d 100644 --- a/content/docs/introducing-jsx.md +++ b/content/docs/introducing-jsx.md @@ -46,7 +46,7 @@ ReactDOM.render( ); ``` -[Try it on CodePen.](http://codepen.io/gaearon/pen/PGEjdG?editors=0010) +Try it on CodePen. We split JSX over multiple lines for readability. While it isn't required, when doing this, we also recommend wrapping it in parentheses to avoid the pitfalls of [automatic semicolon insertion](http://stackoverflow.com/q/2846283). diff --git a/examples/hello-world.js b/examples/hello-world.js new file mode 100644 index 00000000..d0f87a59 --- /dev/null +++ b/examples/hello-world.js @@ -0,0 +1,4 @@ +ReactDOM.render( +

Hello, world!

, + document.getElementById('root') +); diff --git a/examples/index.html b/examples/index.html new file mode 100644 index 00000000..461f1105 --- /dev/null +++ b/examples/index.html @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/examples/introducing-jsx.js b/examples/introducing-jsx.js new file mode 100644 index 00000000..adb32664 --- /dev/null +++ b/examples/introducing-jsx.js @@ -0,0 +1,19 @@ +function formatName(user) { + return user.firstName + ' ' + user.lastName; +} + +const user = { + firstName: 'Harper', + lastName: 'Perez', +}; + +const element = ( +

+ Hello, {formatName(user)}! +

+); + +ReactDOM.render( + element, + document.getElementById('root') +); diff --git a/gatsby-node.js b/gatsby-node.js index 0fc10c4f..5a078ffc 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -8,6 +8,7 @@ const {resolve} = require('path'); const webpack = require('webpack'); +const fs = require('fs'); exports.modifyWebpackConfig = ({config, stage}) => { // See https://github.com/FormidableLabs/react-live/issues/5 @@ -74,11 +75,11 @@ exports.createPages = async ({graphql, boundActionCreators}) => { // (which gets created by Gatsby during a separate phase). } else if ( slug.includes('blog/') || - slug.includes('community/') || - slug.includes('contributing/') || - slug.includes('docs/') || - slug.includes('tutorial/') || - slug.includes('warnings/') + slug.includes('community/') || + slug.includes('contributing/') || + slug.includes('docs/') || + slug.includes('tutorial/') || + slug.includes('warnings/') ) { let template; if (slug.includes('blog/')) { @@ -87,8 +88,8 @@ exports.createPages = async ({graphql, boundActionCreators}) => { template = communityTemplate; } else if ( slug.includes('contributing/') || - slug.includes('docs/') || - slug.includes('warnings/') + slug.includes('docs/') || + slug.includes('warnings/') ) { template = docsTemplate; } else if (slug.includes('tutorial/')) { @@ -117,8 +118,8 @@ exports.createPages = async ({graphql, boundActionCreators}) => { redirect.forEach(fromPath => { if (redirectToSlugMap[fromPath] != null) { console.error(`Duplicate redirect detected from "${fromPath}" to:\n` + - `* ${redirectToSlugMap[fromPath]}\n` + - `* ${slug}\n` + `* ${redirectToSlugMap[fromPath]}\n` + + `* ${slug}\n` ); process.exit(1); } @@ -161,6 +162,29 @@ exports.createPages = async ({graphql, boundActionCreators}) => { redirectInBrowser: true, toPath: newestBlogNode.fields.slug, }); + + // Create Codepen example pages + const htmlTemplate = fs.readFileSync('./examples/index.html', 'utf8'); + fs.readdirSync('./examples').forEach(file => { + // Only create pages for the JS files + if (file.toLowerCase().split('.').pop() === 'js') { + const slug = file.substring(0, file.length - 3); + const jsTemplate = fs.readFileSync(`./examples/${file}`, 'utf8'); + + createPage({ + path: `/examples/${slug}`, + component: resolve('./src/templates/codepen-example.js'), + context: { + slug, + payload: { + html: htmlTemplate, + js: jsTemplate, + }, + }, + }); + } + }); + }; // Parse date information out of blog post filename. diff --git a/package.json b/package.json index 1d214c9f..b6106a10 100644 --- a/package.json +++ b/package.json @@ -84,4 +84,4 @@ "devDependencies": { "eslint-config-prettier": "^2.6.0" } -} +} \ No newline at end of file diff --git a/src/templates/codepen-example.js b/src/templates/codepen-example.js new file mode 100644 index 00000000..7079cc53 --- /dev/null +++ b/src/templates/codepen-example.js @@ -0,0 +1,64 @@ +'use strict'; + +import React, {Component} from 'react'; +import Container from 'components/Container'; +import {colors} from 'theme'; +// import {version} from '../site-constants'; + +// Copied over styles from ButtonLink for the submit btn +const primaryStyle = { + backgroundColor: colors.brand, + color: colors.black, + padding: '10px 25px', + whiteSpace: 'nowrap', + transition: 'background-color 0.2s ease-out', + outline: 0, + border: 'none', + cursor: 'pointer', + + ':hover': { + backgroundColor: colors.white, + }, + + display: 'inline-block', + fontSize: 16, +}; + +class CodepenExample extends Component { + componentDidMount() { + this.codepenForm.submit(); + } + + render() { + const {payload} = this.props.pathContext; + // Set codepen options + payload.js_pre_processor = 'babel'; + // Only have the JS editor open (default for all examples) + payload.editors = '0010'; + // We can pass @version in the URL for version locking, if desired. + payload.js_external = `https://unpkg.com/react/umd/react.development.js;https://unpkg.com/react-dom/umd/react-dom.development.js`; + + return ( + +

Redirecting to Codepen...

+
{ + this.codepenForm = form; + }} + action="https://codepen.io/pen/define" + method="POST"> + + + +
+
+ ); + } +} + +export default CodepenExample; From 37da66e90fba5e3f28512e4eacfa61b678dafd0c Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Mon, 6 Nov 2017 13:24:12 +0000 Subject: [PATCH 2/9] Recommend a real rAF polyfill --- .../reference-javascript-environment-requirements.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/content/docs/reference-javascript-environment-requirements.md b/content/docs/reference-javascript-environment-requirements.md index 39826642..65a58da8 100644 --- a/content/docs/reference-javascript-environment-requirements.md +++ b/content/docs/reference-javascript-environment-requirements.md @@ -23,10 +23,9 @@ ReactDOM.render( ); ``` -React also depends on `requestAnimationFrame` (even in test environments). A simple shim for testing environments would be: +React also depends on `requestAnimationFrame` (even in test environments). +You can use the [raf](https://www.npmjs.com/package/raf) package to shim `requestAnimationFrame`: ```js -global.requestAnimationFrame = function(callback) { - setTimeout(callback, 0); -}; -``` \ No newline at end of file +import 'raf/polyfill'; +``` From b809279c8338e73a6181c87b2d2d9da2c79f5a8c Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 6 Nov 2017 13:32:39 +0000 Subject: [PATCH 3/9] Replaced string.split().pop() with string.endsWith() --- gatsby-node.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/gatsby-node.js b/gatsby-node.js index 942c24c5..4b250d38 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -171,12 +171,7 @@ exports.createPages = async ({graphql, boundActionCreators}) => { const htmlTemplate = fs.readFileSync('./examples/index.html', 'utf8'); fs.readdirSync('./examples').forEach(file => { // Only create pages for the JS files - if ( - file - .toLowerCase() - .split('.') - .pop() === 'js' - ) { + if (file.endsWith('.js')) { const slug = file.substring(0, file.length - 3); const jsTemplate = fs.readFileSync(`./examples/${file}`, 'utf8'); From f14eb61e5f3ce175202c0f91fd2a41d58fe45f49 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 6 Nov 2017 13:37:45 +0000 Subject: [PATCH 4/9] Removed HTML boilerplate from examples folder to simplify build script --- examples/index.html | 3 --- gatsby-node.js | 30 +++++++++++++----------------- 2 files changed, 13 insertions(+), 20 deletions(-) delete mode 100644 examples/index.html diff --git a/examples/index.html b/examples/index.html deleted file mode 100644 index 461f1105..00000000 --- a/examples/index.html +++ /dev/null @@ -1,3 +0,0 @@ -
- -
\ No newline at end of file diff --git a/gatsby-node.js b/gatsby-node.js index 4b250d38..0003ccb7 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -168,25 +168,21 @@ exports.createPages = async ({graphql, boundActionCreators}) => { }); // Create Codepen example pages - const htmlTemplate = fs.readFileSync('./examples/index.html', 'utf8'); fs.readdirSync('./examples').forEach(file => { - // Only create pages for the JS files - if (file.endsWith('.js')) { - const slug = file.substring(0, file.length - 3); - const jsTemplate = fs.readFileSync(`./examples/${file}`, 'utf8'); - - createPage({ - path: `/examples/${slug}`, - component: resolve('./src/templates/codepen-example.js'), - context: { - slug, - payload: { - html: htmlTemplate, - js: jsTemplate, - }, + const slug = file.substring(0, file.length - 3); // Trim extension + const jsTemplate = fs.readFileSync(`./examples/${file}`, 'utf8'); + + createPage({ + path: `/examples/${slug}`, + component: resolve('./src/templates/codepen-example.js'), + context: { + slug, + payload: { + html: '
', + js: jsTemplate, }, - }); - } + }, + }); }); }; From 64e0aade1ef68e624adefcfcb25afe9582b0fd70 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 6 Nov 2017 13:44:45 +0000 Subject: [PATCH 5/9] Refactor Codepen payload a little --- gatsby-node.js | 9 +++------ src/templates/codepen-example.js | 23 ++++++++++++++--------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/gatsby-node.js b/gatsby-node.js index 0003ccb7..b4338712 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -167,20 +167,17 @@ exports.createPages = async ({graphql, boundActionCreators}) => { toPath: newestBlogNode.fields.slug, }); - // Create Codepen example pages + // Create Codepen example pages. fs.readdirSync('./examples').forEach(file => { const slug = file.substring(0, file.length - 3); // Trim extension - const jsTemplate = fs.readFileSync(`./examples/${file}`, 'utf8'); + const code = fs.readFileSync(`./examples/${file}`, 'utf8'); createPage({ path: `/examples/${slug}`, component: resolve('./src/templates/codepen-example.js'), context: { + code, slug, - payload: { - html: '
', - js: jsTemplate, - }, }, }); }); diff --git a/src/templates/codepen-example.js b/src/templates/codepen-example.js index 7079cc53..117682ba 100644 --- a/src/templates/codepen-example.js +++ b/src/templates/codepen-example.js @@ -3,7 +3,11 @@ import React, {Component} from 'react'; import Container from 'components/Container'; import {colors} from 'theme'; -// import {version} from '../site-constants'; + +const EXTERNALS = [ + 'https://unpkg.com/react/umd/react.development.js', + 'https://unpkg.com/react-dom/umd/react-dom.development.js', +]; // Copied over styles from ButtonLink for the submit btn const primaryStyle = { @@ -30,13 +34,14 @@ class CodepenExample extends Component { } render() { - const {payload} = this.props.pathContext; - // Set codepen options - payload.js_pre_processor = 'babel'; - // Only have the JS editor open (default for all examples) - payload.editors = '0010'; - // We can pass @version in the URL for version locking, if desired. - payload.js_external = `https://unpkg.com/react/umd/react.development.js;https://unpkg.com/react-dom/umd/react-dom.development.js`; + // Codepen configuration + const payload = JSON.stringify({ + editors: '0010', // Open JS editor by default + html: '
', + js: this.props.pathContext.code, + js_external: EXTERNALS.join(';'), + js_pre_processor: 'babel', + }); return ( @@ -48,7 +53,7 @@ class CodepenExample extends Component { }} action="https://codepen.io/pen/define" method="POST"> - + Date: Mon, 6 Nov 2017 13:51:45 +0000 Subject: [PATCH 6/9] Tweaked Codepen configuration/options slightly --- src/templates/codepen-example.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/templates/codepen-example.js b/src/templates/codepen-example.js index 117682ba..e3a7eb95 100644 --- a/src/templates/codepen-example.js +++ b/src/templates/codepen-example.js @@ -34,13 +34,16 @@ class CodepenExample extends Component { } render() { - // Codepen configuration + // Codepen configuration. + // https://blog.codepen.io/documentation/api/prefill/ const payload = JSON.stringify({ - editors: '0010', // Open JS editor by default + editors: '0010', html: '
', js: this.props.pathContext.code, js_external: EXTERNALS.join(';'), js_pre_processor: 'babel', + layout: 'left', + title: 'reactjs.org example', }); return ( @@ -55,11 +58,17 @@ class CodepenExample extends Component { method="POST"> - +

+ Not automatically redirecting? + +

+ + +

); From 56735c44a05b45a685797100ac9609faa615f2d3 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 6 Nov 2017 13:59:25 +0000 Subject: [PATCH 7/9] Prettier --- gatsby-node.js | 10 ++++++---- package.json | 2 +- src/templates/codepen-example.js | 11 +++-------- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/gatsby-node.js b/gatsby-node.js index b4338712..19ac95ed 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -6,9 +6,9 @@ 'use strict'; +const {readdirSync, readFileSync} = require('fs'); const {resolve} = require('path'); const webpack = require('webpack'); -const fs = require('fs'); exports.modifyWebpackConfig = ({config, stage}) => { // See https://github.com/FormidableLabs/react-live/issues/5 @@ -167,10 +167,12 @@ exports.createPages = async ({graphql, boundActionCreators}) => { toPath: newestBlogNode.fields.slug, }); - // Create Codepen example pages. - fs.readdirSync('./examples').forEach(file => { + // Create Codepen redirects. + // These use the Codepen prefill API to JIT-create Pens. + // https://blog.codepen.io/documentation/api/prefill/ + readdirSync('./examples').forEach(file => { const slug = file.substring(0, file.length - 3); // Trim extension - const code = fs.readFileSync(`./examples/${file}`, 'utf8'); + const code = readFileSync(`./examples/${file}`, 'utf8'); createPage({ path: `/examples/${slug}`, diff --git a/package.json b/package.json index 573b6e78..9adc56da 100644 --- a/package.json +++ b/package.json @@ -86,4 +86,4 @@ "devDependencies": { "eslint-config-prettier": "^2.6.0" } -} \ No newline at end of file +} diff --git a/src/templates/codepen-example.js b/src/templates/codepen-example.js index e3a7eb95..615b8f7e 100644 --- a/src/templates/codepen-example.js +++ b/src/templates/codepen-example.js @@ -60,14 +60,9 @@ class CodepenExample extends Component {

Not automatically redirecting? - -

- - +
+
+

From 6eef46d1cba2d3da0da29b2dcd6313aa7b9b9b42 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 6 Nov 2017 14:05:14 +0000 Subject: [PATCH 8/9] Renamed 'examples' folder to 'codepen' for clarity --- {examples => codepen}/hello-world.js | 0 {examples => codepen}/introducing-jsx.js | 0 content/docs/hello-world.md | 2 +- content/docs/introducing-jsx.md | 2 +- gatsby-node.js | 6 +++--- 5 files changed, 5 insertions(+), 5 deletions(-) rename {examples => codepen}/hello-world.js (100%) rename {examples => codepen}/introducing-jsx.js (100%) diff --git a/examples/hello-world.js b/codepen/hello-world.js similarity index 100% rename from examples/hello-world.js rename to codepen/hello-world.js diff --git a/examples/introducing-jsx.js b/codepen/introducing-jsx.js similarity index 100% rename from examples/introducing-jsx.js rename to codepen/introducing-jsx.js diff --git a/content/docs/hello-world.md b/content/docs/hello-world.md index 8dba86b3..29c0f839 100644 --- a/content/docs/hello-world.md +++ b/content/docs/hello-world.md @@ -12,7 +12,7 @@ redirect_from: - "docs/getting-started-zh-CN.html" --- -The easiest way to get started with React is to use this Hello World example code on CodePen. You don't need to install anything; you can just open it in another tab and follow along as we go through examples. If you'd rather use a local development environment, check out the [Installation](/docs/installation.html) page. +The easiest way to get started with React is to use this Hello World example code on CodePen. You don't need to install anything; you can just open it in another tab and follow along as we go through examples. If you'd rather use a local development environment, check out the [Installation](/docs/installation.html) page. The smallest React example looks like this: diff --git a/content/docs/introducing-jsx.md b/content/docs/introducing-jsx.md index 85fb0262..11dabf04 100644 --- a/content/docs/introducing-jsx.md +++ b/content/docs/introducing-jsx.md @@ -46,7 +46,7 @@ ReactDOM.render( ); ``` -Try it on CodePen. +Try it on CodePen. We split JSX over multiple lines for readability. While it isn't required, when doing this, we also recommend wrapping it in parentheses to avoid the pitfalls of [automatic semicolon insertion](http://stackoverflow.com/q/2846283). diff --git a/gatsby-node.js b/gatsby-node.js index 19ac95ed..38159549 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -170,12 +170,12 @@ exports.createPages = async ({graphql, boundActionCreators}) => { // Create Codepen redirects. // These use the Codepen prefill API to JIT-create Pens. // https://blog.codepen.io/documentation/api/prefill/ - readdirSync('./examples').forEach(file => { + readdirSync('./codepen').forEach(file => { const slug = file.substring(0, file.length - 3); // Trim extension - const code = readFileSync(`./examples/${file}`, 'utf8'); + const code = readFileSync(`./codepen/${file}`, 'utf8'); createPage({ - path: `/examples/${slug}`, + path: `/codepen/${slug}`, component: resolve('./src/templates/codepen-example.js'), context: { code, From cadaeae62b83b313019af8e719f977828b537ae3 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 6 Nov 2017 14:22:49 +0000 Subject: [PATCH 9/9] Reorganized codepen folder further to support nesting --- .eslintignore | 2 +- .../composing-components.js | 18 +++++++ .../extracting-components-continued.js | 52 +++++++++++++++++++ .../extracting-components.js | 40 ++++++++++++++ .../rendering-a-component.js | 9 ++++ content/docs/components-and-props.md | 8 +-- gatsby-node.js | 10 ++-- package.json | 3 +- yarn.lock | 14 ++++- 9 files changed, 145 insertions(+), 11 deletions(-) create mode 100644 codepen/components-and-props/composing-components.js create mode 100644 codepen/components-and-props/extracting-components-continued.js create mode 100644 codepen/components-and-props/extracting-components.js create mode 100644 codepen/components-and-props/rendering-a-component.js diff --git a/.eslintignore b/.eslintignore index 94254171..705b4afe 100644 --- a/.eslintignore +++ b/.eslintignore @@ -7,4 +7,4 @@ content/* public/* # Ignore examples -examples/* \ No newline at end of file +codepen/* \ No newline at end of file diff --git a/codepen/components-and-props/composing-components.js b/codepen/components-and-props/composing-components.js new file mode 100644 index 00000000..9158dd0c --- /dev/null +++ b/codepen/components-and-props/composing-components.js @@ -0,0 +1,18 @@ +function Welcome(props) { + return

Hello, {props.name}

; +} + +function App() { + return ( +
+ + + +
+ ); +} + +ReactDOM.render( + , + document.getElementById('root') +); \ No newline at end of file diff --git a/codepen/components-and-props/extracting-components-continued.js b/codepen/components-and-props/extracting-components-continued.js new file mode 100644 index 00000000..bcb6547b --- /dev/null +++ b/codepen/components-and-props/extracting-components-continued.js @@ -0,0 +1,52 @@ +function formatDate(date) { + return date.toLocaleDateString(); +} + +function Avatar(props) { + return ( + {props.user.name} + ); +} + +function UserInfo(props) { + return ( +
+ +
+ {props.user.name} +
+
+ ); +} + +function Comment(props) { + return ( +
+ +
+ {props.text} +
+
+ {formatDate(props.date)} +
+
+ ); +} + +const comment = { + date: new Date(), + text: 'I hope you enjoy learning React!', + author: { + name: 'Hello Kitty', + avatarUrl: 'http://placekitten.com/g/64/64' + } +}; +ReactDOM.render( + , + document.getElementById('root') +); \ No newline at end of file diff --git a/codepen/components-and-props/extracting-components.js b/codepen/components-and-props/extracting-components.js new file mode 100644 index 00000000..720624ea --- /dev/null +++ b/codepen/components-and-props/extracting-components.js @@ -0,0 +1,40 @@ +function formatDate(date) { + return date.toLocaleDateString(); +} + +function Comment(props) { + return ( +
+
+ {props.author.name} +
+ {props.author.name} +
+
+
+ {props.text} +
+
+ {formatDate(props.date)} +
+
+ ); +} + +const comment = { + date: new Date(), + text: 'I hope you enjoy learning React!', + author: { + name: 'Hello Kitty', + avatarUrl: 'http://placekitten.com/g/64/64' + } +}; +ReactDOM.render( + , + document.getElementById('root') +); \ No newline at end of file diff --git a/codepen/components-and-props/rendering-a-component.js b/codepen/components-and-props/rendering-a-component.js new file mode 100644 index 00000000..d42e1681 --- /dev/null +++ b/codepen/components-and-props/rendering-a-component.js @@ -0,0 +1,9 @@ +function Welcome(props) { + return

Hello, {props.name}

; +} + +const element = ; +ReactDOM.render( + element, + document.getElementById('root') +); \ No newline at end of file diff --git a/content/docs/components-and-props.md b/content/docs/components-and-props.md index 1bd1f7a6..b6e967c7 100644 --- a/content/docs/components-and-props.md +++ b/content/docs/components-and-props.md @@ -76,7 +76,7 @@ ReactDOM.render( ); ``` -[Try it on CodePen.](http://codepen.io/gaearon/pen/YGYmEG?editors=0010) +Try it on CodePen. Let's recap what happens in this example: @@ -118,7 +118,7 @@ ReactDOM.render( ); ``` -[Try it on CodePen.](http://codepen.io/gaearon/pen/KgQKPr?editors=0010) +Try it on CodePen. Typically, new React apps have a single `App` component at the very top. However, if you integrate React into an existing app, you might start bottom-up with a small component like `Button` and gradually work your way to the top of the view hierarchy. @@ -152,7 +152,7 @@ function Comment(props) { } ``` -[Try it on CodePen.](http://codepen.io/gaearon/pen/VKQwEo?editors=0010) +Try it on CodePen. It accepts `author` (an object), `text` (a string), and `date` (a date) as props, and describes a comment on a social media website. @@ -231,7 +231,7 @@ function Comment(props) { } ``` -[Try it on CodePen.](http://codepen.io/gaearon/pen/rrJNJY?editors=0010) +Try it on CodePen. Extracting components might seem like grunt work at first, but having a palette of reusable components pays off in larger apps. A good rule of thumb is that if a part of your UI is used several times (`Button`, `Panel`, `Avatar`), or is complex enough on its own (`App`, `FeedStory`, `Comment`), it is a good candidate to be a reusable component. diff --git a/gatsby-node.js b/gatsby-node.js index 38159549..359be801 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -6,7 +6,8 @@ 'use strict'; -const {readdirSync, readFileSync} = require('fs'); +const recursiveReaddir = require('recursive-readdir'); +const {readFileSync} = require('fs'); const {resolve} = require('path'); const webpack = require('webpack'); @@ -170,12 +171,13 @@ exports.createPages = async ({graphql, boundActionCreators}) => { // Create Codepen redirects. // These use the Codepen prefill API to JIT-create Pens. // https://blog.codepen.io/documentation/api/prefill/ - readdirSync('./codepen').forEach(file => { + const files = await recursiveReaddir('./codepen'); + files.forEach(file => { const slug = file.substring(0, file.length - 3); // Trim extension - const code = readFileSync(`./codepen/${file}`, 'utf8'); + const code = readFileSync(file, 'utf8'); createPage({ - path: `/codepen/${slug}`, + path: slug, component: resolve('./src/templates/codepen-example.js'), context: { code, diff --git a/package.json b/package.json index 9adc56da..82a862d6 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "reset": "rimraf ./.cache" }, "devDependencies": { - "eslint-config-prettier": "^2.6.0" + "eslint-config-prettier": "^2.6.0", + "recursive-readdir": "^2.2.1" } } diff --git a/yarn.lock b/yarn.lock index a7cd0524..c527a80a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1535,7 +1535,7 @@ bowser@^1.6.0: version "1.7.1" resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.7.1.tgz#a4de8f18a1a0dc9531eb2a92a1521fb6a9ba96a5" -brace-expansion@^1.1.7: +brace-expansion@^1.0.0, brace-expansion@^1.1.7: version "1.1.8" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" dependencies: @@ -6367,6 +6367,12 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: dependencies: brace-expansion "^1.1.7" +minimatch@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -8054,6 +8060,12 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" +recursive-readdir@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.1.tgz#90ef231d0778c5ce093c9a48d74e5c5422d13a99" + dependencies: + minimatch "3.0.3" + redbox-react@^1.3.6: version "1.5.0" resolved "https://registry.yarnpkg.com/redbox-react/-/redbox-react-1.5.0.tgz#04dab11557d26651bf3562a67c22ace56c5d3967"