diff --git a/.eslintignore b/.eslintignore index 942541715..705b4afee 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 000000000..9158dd0cf --- /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 000000000..bcb6547b1 --- /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 000000000..720624ea7 --- /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 000000000..d42e1681c --- /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 1bd1f7a65..b6e967c75 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 381595491..359be8011 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 9adc56da2..82a862d66 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 a7cd0524b..c527a80a1 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"