diff --git a/1-basic-react/README.md b/1-basic-react/README.md new file mode 100644 index 00000000..580ad65b --- /dev/null +++ b/1-basic-react/README.md @@ -0,0 +1,17 @@ +## Instructions to run +1. Navigate to folder */1-basic-react* +2. *NPM install* +3. *NPM run dev* +4. Navigate to localhost:8080 + +## Time stamps from [YouTube video](https://www.youtube.com/watch?v=MhkGQAoc7bc) +* 0:50 Babel overview +* 1:29 Webpack config +* 2:37 NPM install +* 3:13 Looking at client.js & breaking down React +* 5:45 Serving content from file +* 6:18 Live reload w/ npm install -S webpack-dev-server +* 7:10 webpack dev server --content-base src +* 7:55 --Inline --hot (live reload) +* 8:30 Creating a "dev" command in NPM + diff --git a/1-basic-react/package.json b/1-basic-react/package.json index e7402666..9c1ac7e2 100644 --- a/1-basic-react/package.json +++ b/1-basic-react/package.json @@ -4,6 +4,7 @@ "description": "", "main": "webpack.config.js", "dependencies": { + "babel-core": "^6.17.0", "babel-loader": "^6.2.0", "babel-plugin-add-module-exports": "^0.1.2", "babel-plugin-react-html-attrs": "^2.0.0", @@ -19,7 +20,7 @@ }, "devDependencies": {}, "scripts": { - "dev": "./node_modules/.bin/webpack-dev-server --content-base src --inline --hot", + "dev": "webpack-dev-server --content-base src --inline --hot", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", diff --git a/1-basic-react/webpack.config.js b/1-basic-react/webpack.config.js index e31a6282..6ba7dd8f 100644 --- a/1-basic-react/webpack.config.js +++ b/1-basic-react/webpack.config.js @@ -4,7 +4,7 @@ var path = require('path'); module.exports = { context: path.join(__dirname, "src"), - devtool: debug ? "inline-sourcemap" : null, + devtool: debug ? "inline-sourcemap" : false, entry: "./js/client.js", module: { loaders: [ @@ -14,7 +14,7 @@ module.exports = { loader: 'babel-loader', query: { presets: ['react', 'es2015', 'stage-0'], - plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy'], + plugins: ['react-html-attrs', 'transform-decorators-legacy', 'transform-class-properties'], } } ] @@ -25,7 +25,7 @@ module.exports = { }, plugins: debug ? [] : [ new webpack.optimize.DedupePlugin(), - new webpack.optimize.OccurenceOrderPlugin(), + new webpack.optimize.OccurrenceOrderPlugin(), new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }), ], }; diff --git a/2-react-router/package.json b/2-react-router/package.json index 338f9afa..bd03fb8d 100644 --- a/2-react-router/package.json +++ b/2-react-router/package.json @@ -4,6 +4,7 @@ "description": "", "main": "webpack.config.js", "dependencies": { + "babel-core": "^6.17.0", "babel-loader": "^6.2.0", "babel-plugin-add-module-exports": "^0.1.2", "babel-plugin-react-html-attrs": "^2.0.0", diff --git a/2-react-router/src/js/components/layout/Nav.js b/2-react-router/src/js/components/layout/Nav.js index b768499b..5657e27b 100644 --- a/2-react-router/src/js/components/layout/Nav.js +++ b/2-react-router/src/js/components/layout/Nav.js @@ -17,9 +17,9 @@ export default class Nav extends React.Component { render() { const { location } = this.props; const { collapsed } = this.state; - // const featuredClass = location.pathname === "/" ? "active" : ""; - // const archivesClass = location.pathname.match(/^\/archives/) ? "active" : ""; - // const settingsClass = location.pathname.match(/^\/settings/) ? "active" : ""; + const featuredClass = location.pathname === "/" ? "active" : ""; + const archivesClass = location.pathname.match(/^\/archives/) ? "active" : ""; + const settingsClass = location.pathname.match(/^\/settings/) ? "active" : ""; const navClass = collapsed ? "collapse" : ""; return ( @@ -35,13 +35,13 @@ export default class Nav extends React.Component {
diff --git a/3-flux/package.json b/3-flux/package.json index d04fdd7a..61aab93e 100644 --- a/3-flux/package.json +++ b/3-flux/package.json @@ -4,6 +4,7 @@ "description": "", "main": "webpack.config.js", "dependencies": { + "babel-core": "^6.18.2", "babel-loader": "^6.2.0", "babel-plugin-add-module-exports": "^0.1.2", "babel-plugin-react-html-attrs": "^2.0.0", diff --git a/3-flux/src/js/pages/Todos.js b/3-flux/src/js/pages/Todos.js index ff248c83..5e145b9a 100644 --- a/3-flux/src/js/pages/Todos.js +++ b/3-flux/src/js/pages/Todos.js @@ -5,7 +5,7 @@ import * as TodoActions from "../actions/TodoActions"; import TodoStore from "../stores/TodoStore"; -export default class Featured extends React.Component { +export default class Todos extends React.Component { constructor() { super(); this.getTodos = this.getTodos.bind(this); diff --git a/4-redux/package.json b/4-redux/package.json index 5606144d..47461630 100644 --- a/4-redux/package.json +++ b/4-redux/package.json @@ -5,6 +5,7 @@ "main": "webpack.config.js", "dependencies": { "axios": "^0.12.0", + "babel-core": "^6.17.0", "babel-loader": "^6.2.0", "babel-plugin-add-module-exports": "^0.1.2", "babel-plugin-react-html-attrs": "^2.0.0", diff --git a/4-redux/src/js/4-async-middleware.js b/4-redux/src/js/4-async-middleware.js index 777caa1e..235eea33 100644 --- a/4-redux/src/js/4-async-middleware.js +++ b/4-redux/src/js/4-async-middleware.js @@ -21,7 +21,7 @@ const reducer = (state=initialState, action) => { return {...state, fetching: false, error: action.payload} break; } - case "FETCH_USERS_ FULFILLED": { + case "FETCH_USERS_FULFILLED": { return { ...state, fetching: false, diff --git a/5-redux-react/package.json b/5-redux-react/package.json index 141fb42d..bf4c684e 100644 --- a/5-redux-react/package.json +++ b/5-redux-react/package.json @@ -5,6 +5,7 @@ "main": "webpack.config.js", "dependencies": { "axios": "^0.12.0", + "babel-core": "^6.18.2", "babel-loader": "^6.2.0", "babel-plugin-add-module-exports": "^0.1.2", "babel-plugin-react-html-attrs": "^2.0.0", diff --git a/5-redux-react/src/js/actions/tweetsActions.js b/5-redux-react/src/js/actions/tweetsActions.js index cba31e31..87926d0f 100644 --- a/5-redux-react/src/js/actions/tweetsActions.js +++ b/5-redux-react/src/js/actions/tweetsActions.js @@ -2,7 +2,15 @@ import axios from "axios"; export function fetchTweets() { return function(dispatch) { - axios.get("http://rest.learncode.academy/api/test123/tweets") + dispatch({type: "FETCH_TWEETS"}); + + /* + http://rest.learncode.academy is a public test server, so another user's experimentation can break your tests + If you get console errors due to bad data: + - change "reacttest" below to any other username + - post some tweets to http://rest.learncode.academy/api/yourusername/tweets + */ + axios.get("http://rest.learncode.academy/api/reacttest/tweets") .then((response) => { dispatch({type: "FETCH_TWEETS_FULFILLED", payload: response.data}) }) diff --git a/5-redux-react/src/js/components/Layout.js b/5-redux-react/src/js/components/Layout.js index 41517fb3..8d416cd7 100644 --- a/5-redux-react/src/js/components/Layout.js +++ b/5-redux-react/src/js/components/Layout.js @@ -27,7 +27,7 @@ export default class Layout extends React.Component { return } - const mappedTweets = tweets.map(tweet =>
  • {tweet.text}
  • ) + const mappedTweets = tweets.map(tweet =>
  • {tweet.text}
  • ) return

    {user.name}

    diff --git a/6-mobx-react/.babelrc b/6-mobx-react/.babelrc new file mode 100644 index 00000000..1957865a --- /dev/null +++ b/6-mobx-react/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ['react', 'es2015'], + "plugins": ['transform-decorators-legacy', 'transform-class-properties'] +} diff --git a/6-mobx-react/.gitignore b/6-mobx-react/.gitignore new file mode 100644 index 00000000..fd4f2b06 --- /dev/null +++ b/6-mobx-react/.gitignore @@ -0,0 +1,2 @@ +node_modules +.DS_Store diff --git a/6-mobx-react/.nvmrc b/6-mobx-react/.nvmrc new file mode 100644 index 00000000..dffc266d --- /dev/null +++ b/6-mobx-react/.nvmrc @@ -0,0 +1 @@ +v6.3.0 diff --git a/6-mobx-react/package.json b/6-mobx-react/package.json new file mode 100644 index 00000000..2bafc21d --- /dev/null +++ b/6-mobx-react/package.json @@ -0,0 +1,31 @@ +{ + "name": "react-mobx-todos", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "webpack-dev-server --content-base src --inline --hot" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "mobx": "^2.3.7", + "mobx-react": "^3.5.1", + "react": "^15.2.1", + "react-dom": "^15.3.0" + }, + "devDependencies": { + "babel-core": "^6.17.0", + "babel-loader": "^6.2.4", + "babel-plugin-transform-class-properties": "^6.10.2", + "babel-plugin-transform-decorators-legacy": "^1.3.4", + "babel-preset-es2015": "^6.9.0", + "babel-preset-react": "^6.11.1", + "css-loader": "^0.23.1", + "react-addons-test-utils": "^15.3.0", + "style-loader": "^0.13.1", + "webpack": "^1.13.1", + "webpack-dev-server": "^1.14.1" + } +} diff --git a/6-mobx-react/src/css/main.css b/6-mobx-react/src/css/main.css new file mode 100644 index 00000000..8d6ed00c --- /dev/null +++ b/6-mobx-react/src/css/main.css @@ -0,0 +1,50 @@ +html, +body { + margin: 0; + padding: 0; +} + +body { + font-family: 'Slabo 27px', serif; + background: #f5f5f5; + color: #4d4d4d; + min-width: 230px; + max-width: 550px; + margin: 0 auto; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + font-smoothing: antialiased; + font-weight: 300; +} + +input { + border-radius: 5px; + padding: 5px; + border: 1px solid rgba(0,0,0,0.3); + margin-right: 10px +} + +input::-webkit-input-placeholder { + font-style: italic; + font-weight: 300; + color: rgba(0,0,0,0.3); +} + +input::-moz-placeholder { + font-style: italic; + font-weight: 300; + color: rgba(0,0,0,0.3); +} + +input::input-placeholder { + font-style: italic; + font-weight: 300; + color: rgba(0,0,0,0.3); +} + +h1 { + font-weight: 100; + font-size: 100px; + padding:0; + margin: 0; +} diff --git a/6-mobx-react/src/index.html b/6-mobx-react/src/index.html new file mode 100644 index 00000000..a9e74ecd --- /dev/null +++ b/6-mobx-react/src/index.html @@ -0,0 +1,9 @@ + + + + + +
    + + + diff --git a/6-mobx-react/src/js/TodoList.js b/6-mobx-react/src/js/TodoList.js new file mode 100644 index 00000000..b54204a8 --- /dev/null +++ b/6-mobx-react/src/js/TodoList.js @@ -0,0 +1,39 @@ +import React from "react" +import { observer } from "mobx-react" + + +@observer +export default class TodoList extends React.Component { + createNew(e) { + if (e.which === 13) { + this.props.store.createTodo(e.target.value) + e.target.value = "" + } + } + + filter(e) { + this.props.store.filter = e.target.value + } + + toggleComplete(todo) { + todo.complete = !todo.complete + } + + render() { + const { clearComplete, filter, filteredTodos, todos } = this.props.store + + const todoLis = filteredTodos.map(todo => ( +
  • + + {todo.value} +
  • + )) + return
    +

    todos

    + + +
      {todoLis}
    + Clear Complete +
    + } +} diff --git a/6-mobx-react/src/js/TodoStore.js b/6-mobx-react/src/js/TodoStore.js new file mode 100644 index 00000000..7a40b5cd --- /dev/null +++ b/6-mobx-react/src/js/TodoStore.js @@ -0,0 +1,34 @@ +import { computed, observable } from "mobx" + +class Todo { + @observable value + @observable id + @observable complete + + constructor(value) { + this.value = value + this.id = Date.now() + this.complete = false + } +} + +export class TodoStore { + @observable todos = [] + @observable filter = "" + @computed get filteredTodos() { + var matchesFilter = new RegExp(this.filter, "i") + return this.todos.filter(todo => !this.filter || matchesFilter.test(todo.value)) + } + + createTodo(value) { + this.todos.push(new Todo(value)) + } + + clearComplete = () => { + const incompleteTodos = this.todos.filter(todo => !todo.complete) + this.todos.replace(incompleteTodos) + } +} + +export default new TodoStore + diff --git a/6-mobx-react/src/js/main.js b/6-mobx-react/src/js/main.js new file mode 100644 index 00000000..6672df8a --- /dev/null +++ b/6-mobx-react/src/js/main.js @@ -0,0 +1,10 @@ +import "../css/main.css" +import React from "react" +import ReactDOM from "react-dom" +import TodoStore from "./TodoStore" +import TodoList from "./TodoList" + +const app = document.getElementById("app") + +ReactDOM.render(, app) + diff --git a/6-mobx-react/webpack.config.js b/6-mobx-react/webpack.config.js new file mode 100644 index 00000000..de21163e --- /dev/null +++ b/6-mobx-react/webpack.config.js @@ -0,0 +1,29 @@ +var debug = process.env.NODE_ENV !== "production"; +var webpack = require('webpack'); +var path = require('path'); + +module.exports = { + context: path.join(__dirname, "src"), + devtool: debug ? "inline-sourcemap" : null, + entry: "./js/main.js", + module: { + loaders: [ + { + test: /\.js$/, + exclude: /(node_modules|bower_components)/, + loader: 'babel-loader', + query: { presets: ['es2015', 'react'], plugins: ["transform-decorators-legacy", "transform-class-properties"] } + }, + { test: /\.css$/, loader: "style-loader!css-loader" }, + ] + }, + output: { + path: path.join(__dirname, "src"), + filename: "main.min.js" + }, + plugins: debug ? [] : [ + new webpack.optimize.DedupePlugin(), + new webpack.optimize.OccurenceOrderPlugin(), + new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }), + ], +};