From d255c1afc6603202fcee12daa586d7376fc8d7e0 Mon Sep 17 00:00:00 2001 From: Eric Simons Date: Sun, 15 Oct 2017 11:36:37 -0700 Subject: [PATCH 1/8] 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 ff8a5577f95..9425417154d 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 f9be3bde544..06087d7ba59 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 9830ddc93d7..e1e4d64d183 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 00000000000..d0f87a59b75 --- /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 00000000000..461f110596f --- /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 00000000000..adb326643d6 --- /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 0fc10c4f15e..5a078ffc06b 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 1d214c9f022..b6106a1090d 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 00000000000..7079cc53788 --- /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 b809279c8338e73a6181c87b2d2d9da2c79f5a8c Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 6 Nov 2017 13:32:39 +0000 Subject: [PATCH 2/8] 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 942c24c5460..4b250d382ea 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 3/8] 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 461f110596f..00000000000 --- 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 4b250d382ea..0003ccb7067 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 4/8] 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 0003ccb7067..b4338712749 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 7079cc53788..117682baf3c 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 5/8] 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 117682baf3c..e3a7eb95e89 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 6/8] 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 b4338712749..19ac95ed2e4 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 573b6e7856b..9adc56da256 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 e3a7eb95e89..615b8f7efe3 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 7/8] 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 8dba86b3ce6..29c0f839dd5 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 85fb0262962..11dabf044f9 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 19ac95ed2e4..3815954910a 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 8/8] 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 9425417154d..705b4afee1b 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 00000000000..9158dd0cfba --- /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 00000000000..bcb6547b156 --- /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 00000000000..720624ea746 --- /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 00000000000..d42e1681c0d --- /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 1bd1f7a65b2..b6e967c7586 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 3815954910a..359be801126 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 9adc56da256..82a862d6617 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 a7cd0524bdf..c527a80a175 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"