├── README.md
├── badge
└── index.html
├── dropdown
├── .gitignore
├── application.js
├── gulpfile.js
├── index.html
├── package.json
└── src
│ ├── app.jsx
│ ├── button.jsx
│ ├── dropdown.jsx
│ └── list-item.jsx
├── hello-world
└── index.html
├── imgur-client
├── .gitignore
├── README.md
├── gulpfile.js
├── index.html
├── package.json
├── sass
│ ├── header.scss
│ ├── image-detail.scss
│ ├── image-preview.scss
│ ├── style.scss
│ └── topic.scss
└── src
│ ├── actions.jsx
│ ├── app.jsx
│ ├── components
│ ├── comment-box.jsx
│ ├── header.jsx
│ ├── image-detail.jsx
│ ├── image-preview.jsx
│ ├── main.jsx
│ ├── topic-list.jsx
│ └── topic.jsx
│ ├── routes.jsx
│ ├── stores
│ ├── comment-store.jsx
│ ├── image-store.jsx
│ └── topic-store.jsx
│ └── utils
│ └── api.jsx
├── thumbnail-gulp
├── .gitignore
├── application.js
├── gulpfile.js
├── index.html
├── package.json
└── src
│ ├── app.jsx
│ ├── badge.jsx
│ ├── thumbnail-list.jsx
│ └── thumbnail.jsx
├── thumbnail-list
└── index.html
├── thumbnail
└── index.html
└── todos
├── .gitignore
├── README.md
├── application.js
├── gulpfile.js
├── index.html
├── package.json
└── src
├── app.jsx
├── header.jsx
├── list-item.jsx
└── list.jsx
/README.md:
--------------------------------------------------------------------------------
1 | # ReactCasts
2 |
3 | This is the companion git repository for the course Build Web Apps with React JS and Flux.
4 |
5 | Each example from the course can be found within this repo. You can either look at the files
6 | in a completed state, or check out the changes that were made in a particular section
7 | by clicking on one of the links below.
8 |
9 | | Section Number | Section Name | Link to Commit |
10 | |---------------------------------------------------|------------| --- |
11 | | 1 | Introduction | |
12 | | 2 | Link to Github Repository | |
13 | | 3 | JSX Markup in Our Views | |
14 | | 4 | First Application - Basic Building Blocks | [6eac86c](https://github.com/StephenGrider/ReactCasts/commit/c5b1923) |
15 | | 5 | First Application - Creating a React Class | [8ee74dd](https://github.com/StephenGrider/ReactCasts/commit/8ee74dd) |
16 | | 6 | First Application - Showing Content | [df8b9ed](https://github.com/StephenGrider/ReactCasts/commit/df8b9ed) |
17 | | 7 | Exploring Props - Customizing Views | [d67b329](https://github.com/StephenGrider/ReactCasts/commit/d67b329) |
18 | | 8 | Exploring Props - Wiring Up Our Data | [0f49ee5](https://github.com/StephenGrider/ReactCasts/commit/0f49ee5) |
19 | | 9 | Composition - Views Within Views | [5693d3c](https://github.com/StephenGrider/ReactCasts/commit/5693d3c) |
20 | | 10 | Composition - Props Selection | |
21 | | 11 | Lists | [ee7157f](https://github.com/StephenGrider/ReactCasts/commit/ee7157f) |
22 | | 12 | Tooling - Breaking Up Our Code | [3ac4d7c](https://github.com/StephenGrider/ReactCasts/commit/3ac4d7c) |
23 | | 13 | Tooling - Applying NPM | [c3f7c77](https://github.com/StephenGrider/ReactCasts/commit/c3f7c77) |
24 | | 14 | Tooling - Exporting Code | [](https://github.com/StephenGrider/ReactCasts/commit/) |
25 | | 15 | Tooling - Gulpfile | [2112054](https://github.com/StephenGrider/ReactCasts/commit/2112054) |
26 | | 16 | Tooling - Final Refactor | [50d6b89](https://github.com/StephenGrider/ReactCasts/commit/50d6b89) |
27 | | 17 | Exploring State and Events - Purpose of State | [c8c0da4](https://github.com/StephenGrider/ReactCasts/commit/c8c0da4) |
28 | | 18 | Exploring State and Events - Bringing Button Back | [86d0dc1](https://github.com/StephenGrider/ReactCasts/commit/86d0dc1) |
29 | | 19 | Exploring State and Events - Adding Content | [b2bf2d4](https://github.com/StephenGrider/ReactCasts/commit/b2bf2d4) |
30 | | 20 | Exploring State and Events - Toggling Visibility | [3e8921a](https://github.com/StephenGrider/ReactCasts/commit/3e8921a) |
31 | | 21 | Exploring State and Events - Selecting Items | [3625a8d](https://github.com/StephenGrider/ReactCasts/commit/3625a8d) |
32 | | 22 | Firebase - Building From a New Start | |
33 | | 23 | Firebase - Signing up and Integrating Firebase | |
34 | | 24 | Building From a New Start | |
35 | | 25 | Signing up and Integrating Firebase | [2ca16df](https://github.com/StephenGrider/ReactCasts/commit/2ca16df) |
36 | | 26 | Building Our Application Architecture | [4567631](https://github.com/StephenGrider/ReactCasts/commit/4567631) |
37 | | 27 | Hooking Up Our Remote Datastore | [0233b4a](https://github.com/StephenGrider/ReactCasts/commit/0233b4a) |
38 | | 28 | Scaffolding the Header | [74f393e](https://github.com/StephenGrider/ReactCasts/commit/74f393e) |
39 | | 29 | Handling Form Input | [952235f](https://github.com/StephenGrider/ReactCasts/commit/952235f) |
40 | | 30 | Pushing Data to Firebase | [65eae7c](https://github.com/StephenGrider/ReactCasts/commit/65eae7c) |
41 | | 31 | Rendering a List of Items | [6336102](https://github.com/StephenGrider/ReactCasts/commit/6336102) |
42 | | 32 | Waiting on Data Before Rendering | [c9cf6c9](https://github.com/StephenGrider/ReactCasts/commit/c9cf6c9) |
43 | | 33 | Building Item Component | [323226d](https://github.com/StephenGrider/ReactCasts/commit/323226d) |
44 | | 34 | Updating Data to the Remote Datastore | [a466ecb](https://github.com/StephenGrider/ReactCasts/commit/a466ecb) |
45 | | 35 | Debugging Firebase Updating | [631007d](https://github.com/StephenGrider/ReactCasts/commit/631007d) |
46 | | 36 | Allowing Editing and Undoing | [f3d0640](https://github.com/StephenGrider/ReactCasts/commit/f3d0640) |
47 | | 37 | Saving Edit | [4650605](https://github.com/StephenGrider/ReactCasts/commit/4650605) |
48 | | 38 | Bulk Delete Data | [6ff8591](https://github.com/StephenGrider/ReactCasts/commit/6ff8591) |
49 | | 39 | Project Overview | |
50 | | 40 | Imgur API Overview | |
51 | | 41 | Imgur API in Detail | |
52 | | 42 | React Router Demo | [3ea1d06](https://github.com/StephenGrider/ReactCasts/commit/3ea1d06) |
53 | | 43 | Nesting Route | [f268536](https://github.com/StephenGrider/ReactCasts/commit/f268536) |
54 | | 44 | Refactor to Separate Rendering and Routing | [3403ae6](https://github.com/StephenGrider/ReactCasts/commit/3403ae6) |
55 | | 45 | In-App Navigation | [92a5b98](https://github.com/StephenGrider/ReactCasts/commit/92a5b98) |
56 | | 46 | Implementing Fetch | [0d47fe0](https://github.com/StephenGrider/ReactCasts/commit/0d47fe0) |
57 | | 47 | Working with Fetch's Promise | [cacf778](https://github.com/StephenGrider/ReactCasts/commit/cacf778) |
58 | | 48 | Display a List of Topic | [42bcfc6](https://github.com/StephenGrider/ReactCasts/commit/42bcfc6) |
59 | | 49 | Fetching Data Naively | [f6c8c35](https://github.com/StephenGrider/ReactCasts/commit/f6c8c35) |
60 | | 50 | Working With Stores | [f114d82](https://github.com/StephenGrider/ReactCasts/commit/f114d82) |
61 | | 51 | Triggering Changes From a Store | [136aa1f](https://github.com/StephenGrider/ReactCasts/commit/136aa1f) |
62 | | 52 | Working with Action | [10519ed](https://github.com/StephenGrider/ReactCasts/commit/10519ed) |
63 | | 53 | Recap of Flux Data Fetching | |
64 | | 54 | Routing with Parameters | [6c2e386](https://github.com/StephenGrider/ReactCasts/commit/6c2e386) |
65 | | 55 | Matching Parameters | [fcfe2fc](https://github.com/StephenGrider/ReactCasts/commit/fcfe2fc) |
66 | | 56 | Rendering Topics in the Header | [6680a3a](https://github.com/StephenGrider/ReactCasts/commit/6680a3a) |
67 | | 57 | React Router Helper | [b9a82f7](https://github.com/StephenGrider/ReactCasts/commit/b9a82f7) |
68 | | 58 | Implementing Image Store | [c8ea3ad](https://github.com/StephenGrider/ReactCasts/commit/c8ea3ad) |
69 | | 59 | Refetching Data on Rerender | [265e9cd](https://github.com/StephenGrider/ReactCasts/commit/265e9cd) |
70 | | 60 | Scaffolding Image Preview | [b61d75e](https://github.com/StephenGrider/ReactCasts/commit/b61d75e) |
71 | | 61 | Filtering Image Data | [56668a1](https://github.com/StephenGrider/ReactCasts/commit/56668a1) |
72 | | 62 | Playing Videos on Mouseover | [54c0f79](https://github.com/StephenGrider/ReactCasts/commit/54c0f79) |
73 | | 63 | Showing a Play Button for Each Image | [77ef623](https://github.com/StephenGrider/ReactCasts/commit/77ef623) |
74 | | 64 | Adding an Image Stats Overlay | [7c86a66](https://github.com/StephenGrider/ReactCasts/commit/7c86a66) |
75 | | 65 | Scaffolding Image Detail | [e606fad](https://github.com/StephenGrider/ReactCasts/commit/e606fad) |
76 | | 66 | Fetching Single Records from a Store | [2528ac5](https://github.com/StephenGrider/ReactCasts/commit/2528ac5) |
77 | | 67 | Fetching Single Records from a Store Continue | [b573cb7](https://github.com/StephenGrider/ReactCasts/commit/b573cb7) |
78 | | 68 | Rendering an Image Detail | [95af337](https://github.com/StephenGrider/ReactCasts/commit/95af337) |
79 | | 69 | Actions With Multiple Methods | [43e3865](https://github.com/StephenGrider/ReactCasts/commit/43e3865) |
80 | | 70 | Listening to Many Changes in a Component | [a3a6207](https://github.com/StephenGrider/ReactCasts/commit/a3a6207) |
81 | | 71 | CSS Animation | [9bfde96](https://github.com/StephenGrider/ReactCasts/commit/9bfde96) |
82 |
--------------------------------------------------------------------------------
/badge/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
37 |
--------------------------------------------------------------------------------
/dropdown/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | main.js
3 |
--------------------------------------------------------------------------------
/dropdown/application.js:
--------------------------------------------------------------------------------
1 | var options = {
2 | thumbnailData: [{
3 | title: 'Show Courses',
4 | number: 12,
5 | header: 'Learn React',
6 | description: 'React is a fantastic new front end library for rendering web pages. React is a fantastic new front end library for rendering web pages.',
7 | imageUrl: 'https://raw.githubusercontent.com/wiki/facebook/react/react-logo-1000-transparent.png'
8 | },{
9 | title: 'Show Courses',
10 | number: 25,
11 | header: 'Learn Gulp',
12 | description: 'Gulp will speed up your development workflow. Gulp will speed up your development workflow. Gulp will speed up your development workflow.',
13 | imageUrl: 'http://brunch.io/images/others/gulp.png'
14 | }]
15 | };
16 |
17 | var element = React.createElement(ThumbnailList, options);
18 | React.render(element, document.querySelector('.container'));
19 |
20 | var Badge = React.createClass({displayName: "Badge",
21 | render: function() {
22 | return React.createElement("button", {className: "btn btn-primary", type: "button"},
23 | this.props.title, " ", React.createElement("span", {className: "badge"}, this.props.number)
24 | )
25 | }
26 | });
27 |
28 | var ThumbnailList = React.createClass({displayName: "ThumbnailList",
29 | render: function() {
30 | var list = this.props.thumbnailData.map(function(thumbnailProps){
31 | return React.createElement(Thumbnail, React.__spread({}, thumbnailProps))
32 | });
33 |
34 | return React.createElement("div", null,
35 | list
36 | )
37 | }
38 | });
39 |
40 | var Thumbnail = React.createClass({displayName: "Thumbnail",
41 | render: function() {
42 | return React.createElement("div", {className: "col-sm-6 col-md-4"},
43 | React.createElement("div", {className: "thumbnail"},
44 | React.createElement("img", {src: this.props.imageUrl, alt: "..."}),
45 | React.createElement("div", {className: "caption"},
46 | React.createElement("h3", null, this.props.header),
47 | React.createElement("p", null, this.props.description),
48 | React.createElement("p", null,
49 | React.createElement(Badge, {title: this.props.title, number: this.props.number})
50 | )
51 | )
52 | )
53 | )
54 | }
55 | });
56 |
--------------------------------------------------------------------------------
/dropdown/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var gutil = require('gulp-util');
3 | var source = require('vinyl-source-stream');
4 | var browserify = require('browserify');
5 | var watchify = require('watchify');
6 | var reactify = require('reactify');
7 |
8 | gulp.task('default', function() {
9 | var bundler = watchify(browserify({
10 | entries: ['./src/app.jsx'],
11 | transform: [reactify],
12 | extensions: ['.jsx'],
13 | debug: true,
14 | cache: {},
15 | packageCache: {},
16 | fullPaths: true
17 | }));
18 |
19 | function build(file) {
20 | if (file) gutil.log('Recompiling ' + file);
21 | return bundler
22 | .bundle()
23 | .on('error', gutil.log.bind(gutil, 'Browserify Error'))
24 | .pipe(source('main.js'))
25 | .pipe(gulp.dest('./'));
26 | };
27 | build();
28 | bundler.on('update', build);
29 | });
30 |
--------------------------------------------------------------------------------
/dropdown/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/dropdown/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "thumbnail-gulp",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "scripts": {
6 | "test": "echo \"Error: no test specified\" && exit 1"
7 | },
8 | "author": "",
9 | "license": "ISC",
10 | "dependencies": {
11 | "browserify": "^9.0.3",
12 | "gulp": "^3.8.11",
13 | "gulp-concat": "^2.5.2",
14 | "gulp-react": "^3.0.1",
15 | "gulp-util": "^3.0.4",
16 | "react": "^0.13.1",
17 | "reactify": "^1.1.0",
18 | "vinyl-source-stream": "^1.1.0",
19 | "watchify": "^2.4.0"
20 | },
21 | "devDependencies": {}
22 | }
23 |
--------------------------------------------------------------------------------
/dropdown/src/app.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Dropdown = require('./dropdown');
3 |
4 | var options = {
5 | title: 'Choose a dessert', // What should show up on the button to open/close the dropdown
6 | items: [ // List of items to show in the dropdown
7 | 'Apple Pie',
8 | 'Peach Cobbler',
9 | 'Coconut Cream Pie'
10 | ]
11 | };
12 |
13 | var element = React.createElement(Dropdown, options);
14 | React.render(element, document.querySelector('.container'));
15 |
--------------------------------------------------------------------------------
/dropdown/src/button.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | module.exports = React.createClass({
4 | render: function() {
5 | return
9 | }
10 | });
11 |
--------------------------------------------------------------------------------
/dropdown/src/dropdown.jsx:
--------------------------------------------------------------------------------
1 | // We need to show a button and a list
2 | // This component should know when to show the list
3 | // based on when the user clicks on a button
4 |
5 | var React = require('react');
6 | var Button = require('./button');
7 | var ListItem = require('./list-item');
8 |
9 | module.exports = React.createClass({
10 | handleClick: function() {
11 | this.setState({open: !this.state.open});
12 | },
13 | getInitialState: function(){
14 | return { open: false }
15 | },
16 | handleItemClick: function(item) {
17 | this.setState({
18 | open: false,
19 | itemTitle: item
20 | });
21 | },
22 | render: function() {
23 | var list = this.props.items.map(function(item){
24 | return
29 | }.bind(this));
30 |
31 | return
42 | }
43 | });
44 |
--------------------------------------------------------------------------------
/dropdown/src/list-item.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | module.exports = React.createClass({
4 | handleClick: function() {
5 | this.props.whenItemClicked(this.props.item);
6 | },
7 | render: function() {
8 | return
9 | {this.props.item}
10 |
11 | }
12 | });
13 |
--------------------------------------------------------------------------------
/hello-world/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
24 |
--------------------------------------------------------------------------------
/imgur-client/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | main.js
3 | style.css
4 |
--------------------------------------------------------------------------------
/imgur-client/README.md:
--------------------------------------------------------------------------------
1 | ReactStarter
2 | ====
3 |
4 | Use this as a starting point for working on chapters of the [Learn and Understand React JS](https://www.udemy.com/learn-and-understand-reactjs/) course on Udemy.com.
5 |
6 | ---
7 |
8 | ###Getting Started###
9 |
10 | There are two methods for getting started with this repo.
11 |
12 | ####Familiar with Git?#####
13 | Checkout this repo, install depdencies, then start the gulp process with the following:
14 |
15 | ```
16 | > git clone git@github.com:StephenGrider/ReactStarter.git
17 | > cd ReactStarter
18 | > npm install
19 | > gulp
20 | ```
21 |
22 | ####Not Familiar with Git?#####
23 | Click [here](https://github.com/StephenGrider/ReactStarter/releases) then download the .zip file. Extract the contents of the zip file, then open your terminal, change to the project directory, and:
24 |
25 | ```
26 | > npm install
27 | > gulp
28 | ```
29 |
--------------------------------------------------------------------------------
/imgur-client/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var gutil = require('gulp-util');
3 | var source = require('vinyl-source-stream');
4 | var browserify = require('browserify');
5 | var watchify = require('watchify');
6 | var reactify = require('reactify');
7 | var notifier = require('node-notifier');
8 | var server = require('gulp-server-livereload');
9 | var concat = require('gulp-concat');
10 | var sass = require('gulp-sass');
11 | var watch = require('gulp-watch');
12 |
13 | var notify = function(error) {
14 | var message = 'In: ';
15 | var title = 'Error: ';
16 |
17 | if(error.description) {
18 | title += error.description;
19 | } else if (error.message) {
20 | title += error.message;
21 | }
22 |
23 | if(error.filename) {
24 | var file = error.filename.split('/');
25 | message += file[file.length-1];
26 | }
27 |
28 | if(error.lineNumber) {
29 | message += '\nOn Line: ' + error.lineNumber;
30 | }
31 |
32 | notifier.notify({title: title, message: message});
33 | };
34 |
35 | var bundler = watchify(browserify({
36 | entries: ['./src/app.jsx'],
37 | transform: [reactify],
38 | extensions: ['.jsx'],
39 | debug: true,
40 | cache: {},
41 | packageCache: {},
42 | fullPaths: true
43 | }));
44 |
45 | function bundle() {
46 | return bundler
47 | .bundle()
48 | .on('error', notify)
49 | .pipe(source('main.js'))
50 | .pipe(gulp.dest('./'))
51 | }
52 | bundler.on('update', bundle)
53 |
54 | gulp.task('build', function() {
55 | bundle()
56 | });
57 |
58 | gulp.task('serve', function(done) {
59 | gulp.src('')
60 | .pipe(server({
61 | livereload: {
62 | enable: true,
63 | filter: function(filePath, cb) {
64 | if(/main.js/.test(filePath)) {
65 | cb(true)
66 | } else if(/style.css/.test(filePath)){
67 | cb(true)
68 | }
69 | }
70 | },
71 | open: true
72 | }));
73 | });
74 |
75 | gulp.task('sass', function () {
76 | gulp.src('./sass/**/*.scss')
77 | .pipe(sass().on('error', sass.logError))
78 | .pipe(concat('style.css'))
79 | .pipe(gulp.dest('./'));
80 | });
81 |
82 | gulp.task('default', ['build', 'serve', 'sass', 'watch']);
83 |
84 | gulp.task('watch', function () {
85 | gulp.watch('./sass/**/*.scss', ['sass']);
86 | });
87 |
--------------------------------------------------------------------------------
/imgur-client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/imgur-client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-starter",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "scripts": {
6 | "test": "echo \"Error: no test specified\" && exit 1"
7 | },
8 | "author": "",
9 | "license": "ISC",
10 | "dependencies": {
11 | "browserify": "^9.0.3",
12 | "gulp": "^3.8.11",
13 | "gulp-concat": "^2.5.2",
14 | "gulp-react": "^3.0.1",
15 | "gulp-sass": "^2.0.1",
16 | "gulp-server-livereload": "^1.3.0",
17 | "gulp-util": "^3.0.4",
18 | "gulp-watch": "^4.2.4",
19 | "lodash": "^3.10.0",
20 | "node-notifier": "^4.2.1",
21 | "react": "^0.13.3",
22 | "react-router": "1.0.0-beta2",
23 | "reactify": "^1.1.0",
24 | "reflux": "^0.2.8",
25 | "vinyl-source-stream": "^1.1.0",
26 | "watchify": "^2.4.0",
27 | "whatwg-fetch": "^0.9.0"
28 | },
29 | "devDependencies": {}
30 | }
31 |
--------------------------------------------------------------------------------
/imgur-client/sass/header.scss:
--------------------------------------------------------------------------------
1 | .header {
2 | .active {
3 | font-weight: 900;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/imgur-client/sass/image-detail.scss:
--------------------------------------------------------------------------------
1 | .image-detail {
2 | .panel-body {
3 | text-align: center;
4 | }
5 |
6 | img, video {
7 | max-width: 100%;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/imgur-client/sass/image-preview.scss:
--------------------------------------------------------------------------------
1 | .image-preview {
2 | display: inline-block;
3 | position: relative;
4 |
5 | .inset {
6 | position: absolute;
7 | bottom: 5px;
8 | left: 0px;
9 | width: 100%;
10 | background-color: white;
11 | text-align: center;
12 | opacity: .7;
13 | }
14 |
15 | .glyphicon {
16 | position: absolute;
17 | top: 50%;
18 | left: 50%;
19 | transform: translate(-50%, -50%);
20 | font-size: 50px;
21 | opacity: .5;
22 | color: white;
23 | }
24 |
25 | img {
26 | height: 200px;
27 | width: 200px;
28 | display: inline-block;
29 | }
30 |
31 | video {
32 | height: 200px;
33 | width: 200px;
34 | vertical-align: middle;
35 | background-color: black;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/imgur-client/sass/style.scss:
--------------------------------------------------------------------------------
1 | .black {
2 | color: black
3 | }
4 |
--------------------------------------------------------------------------------
/imgur-client/sass/topic.scss:
--------------------------------------------------------------------------------
1 | .topic {
2 | text-align: center;
3 |
4 | .image-preview {
5 | animation: fadein .65s ease-out;
6 |
7 | @keyframes fadein {
8 | 0% {
9 | opacity: 0;
10 | }
11 | 100% {
12 | opacity: 1.0;
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/imgur-client/src/actions.jsx:
--------------------------------------------------------------------------------
1 | var Reflux = require('reflux');
2 |
3 | module.exports = Reflux.createActions([
4 | 'getTopics',
5 | 'getImages',
6 | 'getImage'
7 | ]);
8 |
--------------------------------------------------------------------------------
/imgur-client/src/app.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Routes = require('./routes');
3 | var Api = require('./utils/api');
4 |
5 | React.render(Routes, document.querySelector('.container'));
6 |
--------------------------------------------------------------------------------
/imgur-client/src/components/comment-box.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | module.exports = React.createClass({
4 | render: function(){
5 | return
6 | {this.renderComments()}
7 |
8 | },
9 | renderComments: function() {
10 | return this.props.comments.slice(0, 20).map(function(comment){
11 | return
12 | {comment.ups}
13 | {comment.author}
14 | {comment.comment}
15 |
16 | })
17 | }
18 | });
19 |
--------------------------------------------------------------------------------
/imgur-client/src/components/header.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Router = require('react-router');
3 | var Link = Router.Link;
4 | var Actions = require('../actions');
5 | var TopicStore = require('../stores/topic-store');
6 | var Reflux = require('reflux');
7 |
8 | module.exports = React.createClass({
9 | mixins: [
10 | Reflux.listenTo(TopicStore, 'onChange')
11 | ],
12 | getInitialState: function() {
13 | return {
14 | topics: []
15 | }
16 | },
17 | componentWillMount: function() {
18 | Actions.getTopics();
19 | },
20 | render: function() {
21 | return
31 | },
32 | renderTopics: function() {
33 | return this.state.topics.slice(0, 4).map(function(topic){
34 | return
35 |
36 | {topic.name}
37 |
38 |
39 | });
40 | },
41 | onChange: function(event, topics) {
42 | this.setState({
43 | topics: topics
44 | });
45 | }
46 | });
47 |
--------------------------------------------------------------------------------
/imgur-client/src/components/image-detail.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Reflux = require('reflux');
3 | var ImageStore = require('../stores/image-store');
4 | var CommentStore = require('../stores/comment-store');
5 | var Actions = require('../actions');
6 | var CommentBox = require('./comment-box');
7 |
8 | module.exports = React.createClass({
9 | mixins: [
10 | Reflux.listenTo(ImageStore, 'onChange'),
11 | Reflux.listenTo(CommentStore, 'onChange')
12 | ],
13 | getInitialState: function() {
14 | return {
15 | image: null,
16 | comment: null
17 | }
18 | },
19 | componentWillMount: function() {
20 | Actions.getImage(this.props.params.id);
21 | },
22 | render: function() {
23 | return
24 | {this.state.image ? this.renderContent() : null}
25 |
26 | },
27 | renderContent: function() {
28 | return
29 |
30 |
31 |
{this.state.image.title}
32 |
33 |
34 | {this.renderImage()}
35 |
36 |
37 |
{this.state.image.description}
38 |
39 |
40 |
Comments
41 | {this.renderComments()}
42 |
43 | },
44 | renderComments: function() {
45 | if(!this.state.comments){
46 | return null
47 | }
48 |
49 | return
50 | },
51 | renderImage: function() {
52 | if(this.state.image.animated) {
53 | return
56 | } else {
57 | return
58 | }
59 | },
60 | onChange: function() {
61 | this.setState({
62 | image: ImageStore.find(this.props.params.id),
63 | comments: CommentStore.comment
64 | });
65 | }
66 | });
67 |
--------------------------------------------------------------------------------
/imgur-client/src/components/image-preview.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var ReactRouter = require('react-router');
3 | var Link = ReactRouter.Link;
4 |
5 | module.exports = React.createClass({
6 | getInitialState: function() {
7 | return {
8 | hovering: false
9 | }
10 | },
11 | render: function() {
12 | return
18 | {this.props.animated && this.state.hovering ? this.video() : this.image()}
19 | {this.props.animated && !this.state.hovering ? this.icon() : null }
20 | {this.state.hovering ? this.inset() : null}
21 |
22 | },
23 | inset: function() {
24 | return
25 | Views: {this.props.views}
26 |
27 | Upvotes: {this.props.ups}
28 |
29 | },
30 | image: function() {
31 | var link = 'http://i.imgur.com/' + this.props.id + 'h.jpg';
32 |
33 | return
34 | },
35 | video: function() {
36 | return
37 |
40 |
41 | },
42 | icon: function() {
43 | return
44 | },
45 | handleMouseEnter: function() {
46 | this.setState({hovering: true});
47 | },
48 | handleMouseLeave: function() {
49 | this.setState({hovering: false});
50 | }
51 | });
52 |
--------------------------------------------------------------------------------
/imgur-client/src/components/main.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Header = require('./header');
3 | var TopicList = require('./topic-list');
4 |
5 | module.exports = React.createClass({
6 | render: function() {
7 | return
8 |
9 | {this.content()}
10 |
11 | },
12 | content: function() {
13 | if(this.props.children) {
14 | return this.props.children
15 | } else {
16 | return
17 | }
18 | }
19 | });
20 |
--------------------------------------------------------------------------------
/imgur-client/src/components/topic-list.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Reflux = require('reflux');
3 | var TopicStore = require('../stores/topic-store');
4 | var Actions = require('../actions');
5 | var ReactRouter = require('react-router');
6 | var Link = ReactRouter.Link;
7 |
8 | module.exports = React.createClass({
9 | mixins: [
10 | Reflux.listenTo(TopicStore, 'onChange')
11 | ],
12 | getInitialState: function() {
13 | return {
14 | topics: []
15 | }
16 | },
17 | componentWillMount: function() {
18 | Actions.getTopics();
19 | },
20 | render: function() {
21 | return
22 | {this.renderTopics()}
23 |
24 | },
25 | renderTopics: function() {
26 | return this.state.topics.slice(0, 4).map(function(topic){
27 | return
28 | {topic.name}
29 | {topic.description}
30 |
31 | });
32 | },
33 | onChange: function(event, topics) {
34 | this.setState({topics: topics});
35 | }
36 | });
37 |
--------------------------------------------------------------------------------
/imgur-client/src/components/topic.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Actions = require('../actions');
3 | var ImageStore = require('../stores/image-store');
4 | var Reflux = require('reflux');
5 | var ImagePreview = require('./image-preview');
6 |
7 | module.exports = React.createClass({
8 | mixins: [
9 | Reflux.listenTo(ImageStore, 'onChange')
10 | ],
11 | getInitialState: function() {
12 | return {
13 | images: []
14 | }
15 | },
16 | componentWillMount: function() {
17 | Actions.getImages(this.props.params.id);
18 | },
19 | componentWillReceiveProps: function(nextProps){
20 | Actions.getImages(nextProps.params.id);
21 | },
22 | render: function() {
23 | return
24 | {this.renderImages()}
25 |
26 | },
27 | renderImages: function() {
28 | return this.state.images.slice(0, 20).map(function(image) {
29 | return
30 | });
31 | },
32 | onChange: function(event, images) {
33 | this.setState({images: images})
34 | }
35 | });
36 |
--------------------------------------------------------------------------------
/imgur-client/src/routes.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var ReactRouter = require('react-router');
3 | var HashHistory = require('react-router/lib/hashhistory');
4 | var Router = ReactRouter.Router;
5 | var Route = ReactRouter.Route;
6 |
7 | var Main = require('./components/main');
8 | var Topic = require('./components/topic');
9 | var ImageDetail = require('./components/image-detail');
10 |
11 | module.exports = (
12 |
13 |
14 |
15 |
16 |
17 |
18 | )
19 |
--------------------------------------------------------------------------------
/imgur-client/src/stores/comment-store.jsx:
--------------------------------------------------------------------------------
1 | var Reflux = require('reflux');
2 | var Actions = require('../actions');
3 | var Api = require('../utils/api');
4 |
5 | module.exports = Reflux.createStore({
6 | listenables: [Actions],
7 | getImage: function(id){
8 | Api.get('gallery/' + id + '/comments')
9 | .then(function(json){
10 | this.comment = json.data;
11 | this.triggerChange();
12 | }.bind(this));
13 | },
14 | triggerChange: function() {
15 | this.trigger('change', this.comment);
16 | }
17 | });
18 |
--------------------------------------------------------------------------------
/imgur-client/src/stores/image-store.jsx:
--------------------------------------------------------------------------------
1 | var Reflux = require('reflux');
2 | var Api = require('../utils/api');
3 | var Actions = require('../actions');
4 | var _ = require('lodash');
5 |
6 | module.exports = Reflux.createStore({
7 | listenables: [Actions],
8 | getImages: function(topicId){
9 | Api.get('topics/' + topicId)
10 | .then(function(json){
11 | this.images = _.reject(json.data, function(image) {
12 | return image.is_album
13 | });
14 |
15 | this.triggerChange();
16 | }.bind(this));
17 | },
18 | getImage: function(id) {
19 | Api.get('gallery/image/' + id)
20 | .then(function(json){
21 | if(this.images){
22 | this.images.push(json.data);
23 | } else {
24 | this.images = [json.data];
25 | }
26 |
27 | this.triggerChange();
28 | }.bind(this));
29 | },
30 | find: function(id){
31 | var image = _.findWhere(this.images, {id: id});
32 |
33 | if(image) {
34 | return image
35 | } else {
36 | this.getImage(id);
37 | return null
38 | }
39 | },
40 | triggerChange: function() {
41 | this.trigger('change', this.images);
42 | }
43 | });
44 |
--------------------------------------------------------------------------------
/imgur-client/src/stores/topic-store.jsx:
--------------------------------------------------------------------------------
1 | var Api = require('../utils/api');
2 | var Reflux = require('reflux');
3 | var Actions = require('../actions');
4 |
5 | module.exports = Reflux.createStore({
6 | listenables: [Actions],
7 | getTopics: function() {
8 | return Api.get('topics/defaults')
9 | .then(function(json){
10 | this.topics = json.data;
11 | this.triggerChange();
12 | }.bind(this));
13 | },
14 | triggerChange: function() {
15 | this.trigger('change', this.topics);
16 | }
17 | });
18 |
--------------------------------------------------------------------------------
/imgur-client/src/utils/api.jsx:
--------------------------------------------------------------------------------
1 | var Fetch = require('whatwg-fetch');
2 | var rootUrl = 'https://api.imgur.com/3/';
3 | var apiKey = '430d6820d865788';
4 |
5 | module.exports = {
6 | get: function(url) {
7 | return fetch(rootUrl + url, {
8 | headers: {
9 | 'Authorization': 'Client-ID ' + apiKey
10 | }
11 | })
12 | .then(function(response){
13 | return response.json()
14 | })
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/thumbnail-gulp/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | main.js
3 |
--------------------------------------------------------------------------------
/thumbnail-gulp/application.js:
--------------------------------------------------------------------------------
1 | var options = {
2 | thumbnailData: [{
3 | title: 'Show Courses',
4 | number: 12,
5 | header: 'Learn React',
6 | description: 'React is a fantastic new front end library for rendering web pages. React is a fantastic new front end library for rendering web pages.',
7 | imageUrl: 'https://raw.githubusercontent.com/wiki/facebook/react/react-logo-1000-transparent.png'
8 | },{
9 | title: 'Show Courses',
10 | number: 25,
11 | header: 'Learn Gulp',
12 | description: 'Gulp will speed up your development workflow. Gulp will speed up your development workflow. Gulp will speed up your development workflow.',
13 | imageUrl: 'http://brunch.io/images/others/gulp.png'
14 | }]
15 | };
16 |
17 | var element = React.createElement(ThumbnailList, options);
18 | React.render(element, document.querySelector('.container'));
19 |
20 | var Badge = React.createClass({displayName: "Badge",
21 | render: function() {
22 | return React.createElement("button", {className: "btn btn-primary", type: "button"},
23 | this.props.title, " ", React.createElement("span", {className: "badge"}, this.props.number)
24 | )
25 | }
26 | });
27 |
28 | var ThumbnailList = React.createClass({displayName: "ThumbnailList",
29 | render: function() {
30 | var list = this.props.thumbnailData.map(function(thumbnailProps){
31 | return React.createElement(Thumbnail, React.__spread({}, thumbnailProps))
32 | });
33 |
34 | return React.createElement("div", null,
35 | list
36 | )
37 | }
38 | });
39 |
40 | var Thumbnail = React.createClass({displayName: "Thumbnail",
41 | render: function() {
42 | return React.createElement("div", {className: "col-sm-6 col-md-4"},
43 | React.createElement("div", {className: "thumbnail"},
44 | React.createElement("img", {src: this.props.imageUrl, alt: "..."}),
45 | React.createElement("div", {className: "caption"},
46 | React.createElement("h3", null, this.props.header),
47 | React.createElement("p", null, this.props.description),
48 | React.createElement("p", null,
49 | React.createElement(Badge, {title: this.props.title, number: this.props.number})
50 | )
51 | )
52 | )
53 | )
54 | }
55 | });
56 |
--------------------------------------------------------------------------------
/thumbnail-gulp/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var gutil = require('gulp-util');
3 | var source = require('vinyl-source-stream');
4 | var browserify = require('browserify');
5 | var watchify = require('watchify');
6 | var reactify = require('reactify');
7 |
8 | gulp.task('default', function() {
9 | var bundler = watchify(browserify({
10 | entries: ['./src/app.jsx'],
11 | transform: [reactify],
12 | extensions: ['.jsx'],
13 | debug: true,
14 | cache: {},
15 | packageCache: {},
16 | fullPaths: true
17 | }));
18 |
19 | function build(file) {
20 | if (file) gutil.log('Recompiling ' + file);
21 | return bundler
22 | .bundle()
23 | .on('error', gutil.log.bind(gutil, 'Browserify Error'))
24 | .pipe(source('main.js'))
25 | .pipe(gulp.dest('./'));
26 | };
27 | build();
28 | bundler.on('update', build);
29 | });
30 |
--------------------------------------------------------------------------------
/thumbnail-gulp/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/thumbnail-gulp/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "thumbnail-gulp",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "scripts": {
6 | "test": "echo \"Error: no test specified\" && exit 1"
7 | },
8 | "author": "",
9 | "license": "ISC",
10 | "dependencies": {
11 | "browserify": "^9.0.3",
12 | "gulp": "^3.8.11",
13 | "gulp-concat": "^2.5.2",
14 | "gulp-react": "^3.0.1",
15 | "gulp-util": "^3.0.4",
16 | "react": "^0.13.3",
17 | "reactify": "^1.1.0",
18 | "vinyl-source-stream": "^1.1.0",
19 | "watchify": "^2.4.0"
20 | },
21 | "devDependencies": {}
22 | }
23 |
--------------------------------------------------------------------------------
/thumbnail-gulp/src/app.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var ThumbnailList = require('./thumbnail-list');
3 |
4 | var options = {
5 | thumbnailData: [{
6 | title: 'Show Courses',
7 | number: 120,
8 | header: 'Learn React',
9 | description: 'React is a fantastic new front end library for rendering web pages. React is a fantastic new front end library for rendering web pages.',
10 | imageUrl: 'https://raw.githubusercontent.com/wiki/facebook/react/react-logo-1000-transparent.png'
11 | },{
12 | title: 'Show Courses',
13 | number: 25,
14 | header: 'Learn Gulp',
15 | description: 'Gulp will speed up your development workflow. Gulp will speed up your development workflow. Gulp will speed up your development workflow.',
16 | imageUrl: 'http://brunch.io/images/others/gulp.png'
17 | }]
18 | };
19 |
20 |
21 | var element = React.createElement(ThumbnailList, options);
22 | React.render(element, document.querySelector('.container'));
23 |
--------------------------------------------------------------------------------
/thumbnail-gulp/src/badge.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | module.exports = React.createClass({
4 | render: function() {
5 | return
8 | }
9 | });
10 |
--------------------------------------------------------------------------------
/thumbnail-gulp/src/thumbnail-list.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Thumbnail = require('./thumbnail');
3 |
4 | module.exports = React.createClass({
5 | render: function() {
6 | var list = this.props.thumbnailData.map(function(thumbnailProps){
7 | return
8 | });
9 |
10 | return
11 | {list}
12 |
13 | }
14 | });
15 |
--------------------------------------------------------------------------------
/thumbnail-gulp/src/thumbnail.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Badge = require('./badge');
3 |
4 | module.exports = React.createClass({
5 | render: function() {
6 | return
7 |
8 |

9 |
10 |
{this.props.header}
11 |
{this.props.description}
12 |
13 |
14 |
15 |
16 |
17 |
18 | }
19 | });
20 |
--------------------------------------------------------------------------------
/thumbnail-list/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
68 |
--------------------------------------------------------------------------------
/thumbnail/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
48 |
--------------------------------------------------------------------------------
/todos/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | main.js
3 |
--------------------------------------------------------------------------------
/todos/README.md:
--------------------------------------------------------------------------------
1 | ReactStarter
2 | ====
3 |
4 | Use this as a starting point for working on chapters of the [Learn and Understand React JS](https://www.udemy.com/learn-and-understand-reactjs/) course on Udemy.com.
5 |
6 | ---
7 |
8 | ###Getting Started###
9 |
10 | There are two methods for getting started with this repo.
11 |
12 | ####Familiar with Git?#####
13 | Checkout this repo, install depdencies, then start the gulp process with the following:
14 |
15 | ```
16 | > git clone git@github.com:StephenGrider/ReactStarter.git
17 | > cd ReactStarter
18 | > npm install
19 | > gulp
20 | ```
21 |
22 | ####Not Familiar with Git?#####
23 | Click [here](https://github.com/StephenGrider/ReactStarter/releases) then download the .zip file. Extract the contents of the zip file, then open your terminal, change to the project directory, and:
24 |
25 | ```
26 | > npm install
27 | > gulp
28 | ```
29 |
--------------------------------------------------------------------------------
/todos/application.js:
--------------------------------------------------------------------------------
1 | var options = {
2 | thumbnailData: [{
3 | title: 'Show Courses',
4 | number: 12,
5 | header: 'Learn React',
6 | description: 'React is a fantastic new front end library for rendering web pages. React is a fantastic new front end library for rendering web pages.',
7 | imageUrl: 'https://raw.githubusercontent.com/wiki/facebook/react/react-logo-1000-transparent.png'
8 | },{
9 | title: 'Show Courses',
10 | number: 25,
11 | header: 'Learn Gulp',
12 | description: 'Gulp will speed up your development workflow. Gulp will speed up your development workflow. Gulp will speed up your development workflow.',
13 | imageUrl: 'http://brunch.io/images/others/gulp.png'
14 | }]
15 | };
16 |
17 | var element = React.createElement(ThumbnailList, options);
18 | React.render(element, document.querySelector('.container'));
19 |
20 | var Badge = React.createClass({displayName: "Badge",
21 | render: function() {
22 | return React.createElement("button", {className: "btn btn-primary", type: "button"},
23 | this.props.title, " ", React.createElement("span", {className: "badge"}, this.props.number)
24 | )
25 | }
26 | });
27 |
28 | var ThumbnailList = React.createClass({displayName: "ThumbnailList",
29 | render: function() {
30 | var list = this.props.thumbnailData.map(function(thumbnailProps){
31 | return React.createElement(Thumbnail, React.__spread({}, thumbnailProps))
32 | });
33 |
34 | return React.createElement("div", null,
35 | list
36 | )
37 | }
38 | });
39 |
40 | var Thumbnail = React.createClass({displayName: "Thumbnail",
41 | render: function() {
42 | return React.createElement("div", {className: "col-sm-6 col-md-4"},
43 | React.createElement("div", {className: "thumbnail"},
44 | React.createElement("img", {src: this.props.imageUrl, alt: "..."}),
45 | React.createElement("div", {className: "caption"},
46 | React.createElement("h3", null, this.props.header),
47 | React.createElement("p", null, this.props.description),
48 | React.createElement("p", null,
49 | React.createElement(Badge, {title: this.props.title, number: this.props.number})
50 | )
51 | )
52 | )
53 | )
54 | }
55 | });
56 |
--------------------------------------------------------------------------------
/todos/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var gutil = require('gulp-util');
3 | var source = require('vinyl-source-stream');
4 | var browserify = require('browserify');
5 | var watchify = require('watchify');
6 | var reactify = require('reactify');
7 | var notifier = require('node-notifier');
8 | var server = require('gulp-server-livereload');
9 |
10 | var notify = function(error) {
11 | var message = 'In: ';
12 | var title = 'Error: ';
13 |
14 | if(error.description) {
15 | title += error.description;
16 | } else if (error.message) {
17 | title += error.message;
18 | }
19 |
20 | if(error.filename) {
21 | var file = error.filename.split('/');
22 | message += file[file.length-1];
23 | }
24 |
25 | if(error.lineNumber) {
26 | message += '\nOn Line: ' + error.lineNumber;
27 | }
28 |
29 | notifier.notify({title: title, message: message});
30 | };
31 |
32 | var bundler = watchify(browserify({
33 | entries: ['./src/app.jsx'],
34 | transform: [reactify],
35 | extensions: ['.jsx'],
36 | debug: true,
37 | cache: {},
38 | packageCache: {},
39 | fullPaths: true
40 | }));
41 |
42 | function bundle() {
43 | return bundler
44 | .bundle()
45 | .on('error', notify)
46 | .pipe(source('main.js'))
47 | .pipe(gulp.dest('./'))
48 | }
49 | bundler.on('update', bundle)
50 |
51 | gulp.task('build', function() {
52 | bundle()
53 | });
54 |
55 | gulp.task('serve', function(done) {
56 | gulp.src('')
57 | .pipe(server({
58 | livereload: {
59 | enable: true,
60 | filter: function(filePath, cb) {
61 | cb( /main.js/.test(filePath) )
62 | }
63 | },
64 | open: true
65 | }));
66 | });
67 |
68 | gulp.task('default', ['build', 'serve']);
69 |
--------------------------------------------------------------------------------
/todos/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/todos/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-starter",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "scripts": {
6 | "test": "echo \"Error: no test specified\" && exit 1"
7 | },
8 | "author": "",
9 | "license": "ISC",
10 | "dependencies": {
11 | "browserify": "^9.0.3",
12 | "firebase": "^2.2.6",
13 | "gulp": "^3.8.11",
14 | "gulp-concat": "^2.5.2",
15 | "gulp-react": "^3.0.1",
16 | "gulp-server-livereload": "^1.3.0",
17 | "gulp-util": "^3.0.4",
18 | "node-notifier": "^4.2.1",
19 | "react": "^0.13.1",
20 | "reactfire": "^0.4.0",
21 | "reactify": "^1.1.0",
22 | "vinyl-source-stream": "^1.1.0",
23 | "watchify": "^2.4.0"
24 | },
25 | "devDependencies": {}
26 | }
27 |
--------------------------------------------------------------------------------
/todos/src/app.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var ReactFire = require('reactfire');
3 | var Firebase = require('firebase');
4 | var Header = require('./header');
5 | var List = require('./list');
6 | var rootUrl = 'https://blistering-torch-4253.firebaseio.com/';
7 |
8 | var App = React.createClass({
9 | mixins: [ ReactFire ],
10 | getInitialState: function() {
11 | return {
12 | items: {},
13 | loaded: false
14 | }
15 | },
16 | componentWillMount: function() {
17 | this.fb = new Firebase(rootUrl + 'items/');
18 | this.bindAsObject(this.fb, 'items');
19 | this.fb.on('value', this.handleDataLoaded);
20 | },
21 | render: function() {
22 | return
23 |
24 |
25 | To-Do List
26 |
27 |
28 |
29 |
30 |
31 | {this.deleteButton()}
32 |
33 |
34 |
35 | },
36 | deleteButton: function() {
37 | if(!this.state.loaded) {
38 | return
39 | } else {
40 | return
41 |
42 |
48 |
49 | }
50 | },
51 | onDeleteDoneClick: function() {
52 | for(var key in this.state.items) {
53 | if(this.state.items[key].done === true) {
54 | this.fb.child(key).remove();
55 | }
56 | }
57 | },
58 | handleDataLoaded: function(){
59 | this.setState({loaded: true});
60 | }
61 | });
62 |
63 | var element = React.createElement(App, {});
64 | React.render(element, document.querySelector('.container'));
65 |
--------------------------------------------------------------------------------
/todos/src/header.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | module.exports = React.createClass({
4 | getInitialState: function() {
5 | return {
6 | text: ''
7 | }
8 | },
9 | render: function() {
10 | return
11 |
16 |
17 |
23 |
24 |
25 | },
26 | handleClick: function() {
27 | this.props.itemsStore.push({
28 | text: this.state.text,
29 | done: false
30 | });
31 |
32 | this.setState({text: ''});
33 | },
34 | handleInputChange: function(event) {
35 | this.setState({text: event.target.value});
36 | }
37 | });
38 |
--------------------------------------------------------------------------------
/todos/src/list-item.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Firebase = require('firebase');
3 | var rootUrl = 'https://blistering-torch-4253.firebaseio.com/';
4 |
5 | module.exports = React.createClass({
6 | getInitialState: function() {
7 | return {
8 | text: this.props.item.text,
9 | done: this.props.item.done,
10 | textChanged: false
11 | }
12 | },
13 | componentWillMount: function() {
14 | this.fb = new Firebase(rootUrl + 'items/' + this.props.item.key);
15 | },
16 | render: function() {
17 | return
18 |
19 |
24 |
25 |
31 |
32 | {this.changesButtons()}
33 |
39 |
40 |
41 | },
42 | changesButtons: function() {
43 | if(!this.state.textChanged) {
44 | return null
45 | } else {
46 | return [
47 | ,
53 |
59 | ]
60 | }
61 | },
62 | handleSaveClick: function() {
63 | this.fb.update({text: this.state.text});
64 | this.setState({textChanged: false});
65 | },
66 | handleUndoClick: function() {
67 | this.setState({
68 | text: this.props.item.text,
69 | textChanged: false
70 | });
71 | },
72 | handleTextChange: function(event) {
73 | this.setState({
74 | text: event.target.value,
75 | textChanged: true
76 | });
77 | },
78 | handleDoneChange: function(event) {
79 | var update = {done: event.target.checked}
80 | this.setState(update);
81 | this.fb.update(update);
82 | },
83 | handleDeleteClick: function() {
84 | this.fb.remove();
85 | }
86 | });
87 |
--------------------------------------------------------------------------------
/todos/src/list.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var ListItem = require('./list-item');
3 |
4 | module.exports = React.createClass({
5 | render: function() {
6 | return
7 | {this.renderList()}
8 |
9 | },
10 | renderList: function() {
11 | if(!this.props.items) {
12 | return
13 | Add a todo to get started.
14 |
15 | } else {
16 | var children = [];
17 |
18 | for(var key in this.props.items) {
19 | var item = this.props.items[key];
20 | item.key = key;
21 |
22 | children.push(
23 |
27 |
28 | )
29 | }
30 |
31 | return children;
32 | }
33 | }
34 | });
35 |
--------------------------------------------------------------------------------