Skip to content

Seamlessly sync examples from Github -> Codepen #245

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Nov 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ node_modules/*
content/*

# Ignore built files
public/*
public/*

# Ignore examples
codepen/*
18 changes: 18 additions & 0 deletions codepen/components-and-props/composing-components.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}

function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}

ReactDOM.render(
<App />,
document.getElementById('root')
);
52 changes: 52 additions & 0 deletions codepen/components-and-props/extracting-components-continued.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
function formatDate(date) {
return date.toLocaleDateString();
}

function Avatar(props) {
return (
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name} />
);
}

function UserInfo(props) {
return (
<div className="UserInfo">
<Avatar user={props.user} />
<div className="UserInfo-name">
{props.user.name}
</div>
</div>
);
}

function Comment(props) {
return (
<div className="Comment">
<UserInfo user={props.author} />
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}

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(
<Comment
date={comment.date}
text={comment.text}
author={comment.author} />,
document.getElementById('root')
);
40 changes: 40 additions & 0 deletions codepen/components-and-props/extracting-components.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
function formatDate(date) {
return date.toLocaleDateString();
}

function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name} />
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}

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(
<Comment
date={comment.date}
text={comment.text}
author={comment.author} />,
document.getElementById('root')
);
9 changes: 9 additions & 0 deletions codepen/components-and-props/rendering-a-component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}

const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
4 changes: 4 additions & 0 deletions codepen/hello-world.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
19 changes: 19 additions & 0 deletions codepen/introducing-jsx.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}

const user = {
firstName: 'Harper',
lastName: 'Perez',
};

const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);

ReactDOM.render(
element,
document.getElementById('root')
);
8 changes: 4 additions & 4 deletions content/docs/components-and-props.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ ReactDOM.render(
);
```

[Try it on CodePen.](http://codepen.io/gaearon/pen/YGYmEG?editors=0010)
<a href="/codepen/components-and-props/rendering-a-component" target="_blank">Try it on CodePen</a>.

Let's recap what happens in this example:

Expand Down Expand Up @@ -118,7 +118,7 @@ ReactDOM.render(
);
```

[Try it on CodePen.](http://codepen.io/gaearon/pen/KgQKPr?editors=0010)
<a href="/codepen/components-and-props/composing-components" target="_blank">Try it on CodePen</a>.

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.

Expand Down Expand Up @@ -152,7 +152,7 @@ function Comment(props) {
}
```

[Try it on CodePen.](http://codepen.io/gaearon/pen/VKQwEo?editors=0010)
<a href="/codepen/components-and-props/extracting-components" target="_blank">Try it on CodePen</a>.

It accepts `author` (an object), `text` (a string), and `date` (a date) as props, and describes a comment on a social media website.

Expand Down Expand Up @@ -231,7 +231,7 @@ function Comment(props) {
}
```

[Try it on CodePen.](http://codepen.io/gaearon/pen/rrJNJY?editors=0010)
<a href="/codepen/components-and-props/extracting-components-continued" target="_blank">Try it on CodePen</a>.

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.

Expand Down
2 changes: 1 addition & 1 deletion content/docs/hello-world.md
Original file line number Diff line number Diff line change
Expand Up @@ -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](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 <a href="/codepen/hello-world" target="_blank">this Hello World example code on CodePen</a>. 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:

Expand Down
2 changes: 1 addition & 1 deletion content/docs/introducing-jsx.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ ReactDOM.render(
);
```

[Try it on CodePen.](http://codepen.io/gaearon/pen/PGEjdG?editors=0010)
<a href="/codepen/introducing-jsx" target="_blank">Try it on CodePen.</a>

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).

Expand Down
20 changes: 20 additions & 0 deletions gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

'use strict';

const recursiveReaddir = require('recursive-readdir');
const {readFileSync} = require('fs');
const {resolve} = require('path');
const webpack = require('webpack');

Expand Down Expand Up @@ -165,6 +167,24 @@ exports.createPages = async ({graphql, boundActionCreators}) => {
redirectInBrowser: true,
toPath: newestBlogNode.fields.slug,
});

// Create Codepen redirects.
// These use the Codepen prefill API to JIT-create Pens.
// https://blog.codepen.io/documentation/api/prefill/
const files = await recursiveReaddir('./codepen');
files.forEach(file => {
const slug = file.substring(0, file.length - 3); // Trim extension
const code = readFileSync(file, 'utf8');

createPage({
path: slug,
component: resolve('./src/templates/codepen-example.js'),
context: {
code,
slug,
},
});
});
};

// Parse date information out of blog post filename.
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
73 changes: 73 additions & 0 deletions src/templates/codepen-example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
'use strict';

import React, {Component} from 'react';
import Container from 'components/Container';
import {colors} from 'theme';

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 = {
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() {
// Codepen configuration.
// https://blog.codepen.io/documentation/api/prefill/
const payload = JSON.stringify({
editors: '0010',
html: '<div id="root"></div>',
js: this.props.pathContext.code,
js_external: EXTERNALS.join(';'),
js_pre_processor: 'babel',
layout: 'left',
title: 'reactjs.org example',
});

return (
<Container>
<h1>Redirecting to Codepen...</h1>
<form
style={{paddingBottom: '50px'}}
ref={form => {
this.codepenForm = form;
}}
action="https://codepen.io/pen/define"
method="POST">
<input type="hidden" name="data" value={payload} />

<p>
Not automatically redirecting?
<br />
<br />
<input style={primaryStyle} type="submit" value="Click here" />
</p>
</form>
</Container>
);
}
}

export default CodepenExample;
14 changes: 13 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down