diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..daeba5f9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*~
+node_modules
+.DS_Store
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..a0001786
--- /dev/null
+++ b/README.md
@@ -0,0 +1,12 @@
+# React comment box example
+
+This is the React comment box example from [the React tutorial](http://facebook.github.io/react/docs/tutorial.html).
+
+## To use
+
+```
+npm install express
+node server.js
+```
+
+And visit http://localhost:3000/. Try opening multiple tabs!
diff --git a/css/base.css b/css/base.css
new file mode 100755
index 00000000..3ed9ea38
--- /dev/null
+++ b/css/base.css
@@ -0,0 +1,62 @@
+body {
+ background: #fff;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;;
+ font-size: 15px;
+ line-height: 1.7;
+ margin: 0;
+ padding: 30px;
+}
+
+a {
+ color: #4183c4;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+code {
+ background-color: #f8f8f8;
+ border: 1px solid #ddd;
+ border-radius: 3px;
+ font-family: "Bitstream Vera Sans Mono", Consolas, Courier, monospace;
+ font-size: 12px;
+ margin: 0 2px;
+ padding: 0px 5px;
+}
+
+h1, h2, h3, h4 {
+ font-weight: bold;
+ margin: 0 0 15px;
+ padding: 0;
+}
+
+h1 {
+ border-bottom: 1px solid #ddd;
+ font-size: 2.5em;
+ font-weight: bold;
+ margin: 0 0 15px;
+ padding: 0;
+}
+
+h2 {
+ border-bottom: 1px solid #eee;
+ font-size: 2em;
+}
+
+h3 {
+ font-size: 1.5em;
+}
+
+h4 {
+ font-size: 1.2em;
+}
+
+p, ul {
+ margin: 15px 0;
+}
+
+ul {
+ padding-left: 30px;
+}
diff --git a/index.html b/index.html
new file mode 100755
index 00000000..defed026
--- /dev/null
+++ b/index.html
@@ -0,0 +1,16 @@
+
+
+
+ Hello React
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..8ed1b242
--- /dev/null
+++ b/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "react-tutorial",
+ "version": "0.0.0",
+ "description": "Code from the React tutorial.",
+ "main": "server.js",
+ "dependencies": {
+ "express": "3.12.1"
+ },
+ "devDependencies": {},
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "start": "node server.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/petehunt/react-tutorial.git"
+ },
+ "keywords": [
+ "react",
+ "tutorial",
+ "comment",
+ "example"
+ ],
+ "author": "petehunt",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/petehunt/react-tutorial/issues"
+ },
+ "homepage": "https://github.com/petehunt/react-tutorial"
+}
diff --git a/scripts/example.js b/scripts/example.js
new file mode 100755
index 00000000..8fa001ed
--- /dev/null
+++ b/scripts/example.js
@@ -0,0 +1,114 @@
+/** @jsx React.DOM */
+
+var converter = new Showdown.converter();
+
+var Comment = React.createClass({
+ render: function() {
+ var rawMarkup = converter.makeHtml(this.props.children.toString());
+ return (
+
+
+ {this.props.author}
+
+
+
+ );
+ }
+});
+
+var CommentBox = React.createClass({
+ loadCommentsFromServer: function() {
+ $.ajax({
+ url: this.props.url,
+ dataType: 'json',
+ success: function(data) {
+ this.setState({data: data});
+ }.bind(this),
+ error: function(xhr, status, err) {
+ console.error(this.props.url, status, err.toString());
+ }.bind(this)
+ });
+ },
+ handleCommentSubmit: function(comment) {
+ var comments = this.state.data;
+ comments.push(comment);
+ this.setState({data: comments}, function() {
+ // `setState` accepts a callback. To avoid (improbable) race condition,
+ // `we'll send the ajax request right after we optimistically set the new
+ // `state.
+ $.ajax({
+ url: this.props.url,
+ dataType: 'json',
+ type: 'POST',
+ data: comment,
+ success: function(data) {
+ this.setState({data: data});
+ }.bind(this),
+ error: function(xhr, status, err) {
+ console.error(this.props.url, status, err.toString());
+ }.bind(this)
+ });
+ });
+ },
+ getInitialState: function() {
+ return {data: []};
+ },
+ componentWillMount: function() {
+ this.loadCommentsFromServer();
+ setInterval(this.loadCommentsFromServer, this.props.pollInterval);
+ },
+ render: function() {
+ return (
+
+
Comments
+
+
+
+ );
+ }
+});
+
+var CommentList = React.createClass({
+ render: function() {
+ var commentNodes = this.props.data.map(function(comment, index) {
+ return (
+ // `key` is a React-specific concept and is not mandatory for the
+ // purpose of this tutorial. if you're curious, see more here:
+ // http://facebook.github.io/react/docs/multiple-components.html#dynamic-children
+
+ {comment.text}
+
+ );
+ });
+ return (
+
+ {commentNodes}
+
+ );
+ }
+});
+
+var CommentForm = React.createClass({
+ handleSubmit: function() {
+ var author = this.refs.author.getDOMNode().value.trim();
+ var text = this.refs.text.getDOMNode().value.trim();
+ this.props.onCommentSubmit({author: author, text: text});
+ this.refs.author.getDOMNode().value = '';
+ this.refs.text.getDOMNode().value = '';
+ return false;
+ },
+ render: function() {
+ return (
+
+ );
+ }
+});
+
+React.renderComponent(
+ ,
+ document.getElementById('content')
+);
diff --git a/server.js b/server.js
new file mode 100644
index 00000000..4213ab59
--- /dev/null
+++ b/server.js
@@ -0,0 +1,20 @@
+var express = require('express');
+var app = express();
+
+var comments = [{author: 'Pete Hunt', text: 'Hey there!'}];
+
+app.use('/', express.static(__dirname));
+app.use(express.bodyParser());
+
+app.get('/comments.json', function(req, res) {
+ res.setHeader('Content-Type', 'application/json');
+ res.send(JSON.stringify(comments));
+});
+
+app.post('/comments.json', function(req, res) {
+ comments.push(req.body);
+ res.setHeader('Content-Type', 'application/json');
+ res.send(JSON.stringify(comments));
+});
+
+app.listen(3000);