diff --git a/README.md b/README.md index 9597d74..5c3fb85 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,26 @@ -Kanban React.js App -===================== +Kanban React.js App - Chapter 1 +================================= -Kanban-style project management tool built throughout the Pro React book +Kanban-style project management tool built throughout the Pro React book. End of chapter 1. -![Snapshot](https://cloud.githubusercontent.com/assets/33676/10969936/76e8f39e-83b2-11e5-8a36-0c5632850711.png) +### Summary + +Implemented the basic structure of the project. All data is hard-coded and React warns about missing `key` props (which are implemented in chapter 2). + +![end_of_chapter1](https://cloud.githubusercontent.com/assets/33676/10971478/9db2d9d2-83bb-11e5-8603-5a19b21376a8.png) ### How the repository is organized +You are in the Chapter 1 Branch. + The repository is organized in branches: Each branch corresponds to the end of a specific chapter. The master branch contains the final source code. After cloning and fetching all of the remote branches, you can switch branches using `git checkout`, for example: ``` git clone git@github.com:pro-react/kanban-app.git -git fetch +git fetch --all git checkout chapter3 ``` diff --git a/app/App.js b/app/App.js new file mode 100755 index 0000000..e7fe28e --- /dev/null +++ b/app/App.js @@ -0,0 +1 @@ +import React from 'react'; import {render} from 'react-dom'; import KanbanBoard from './KanbanBoard'; let cardsList = [ { id: 1, title: "Read the Book", description: "I should read the whole book", status: "in-progress", tasks: [] }, { id: 2, title: "Write some code", description: "Code along with the samples in the book", status: "todo", tasks: [ { id: 1, name: "ContactList Example", done: true }, { id: 2, name: "Kanban Example", done: false }, { id: 3, name: "My own experiments", done: false } ] } ]; render(, document.getElementById('root')); \ No newline at end of file diff --git a/app/Card.js b/app/Card.js new file mode 100644 index 0000000..856627d --- /dev/null +++ b/app/Card.js @@ -0,0 +1,33 @@ +import React, { Component } from 'react'; +import CheckList from './CheckList'; + +class Card extends Component { + constructor() { + super(...arguments); + this.state = { + showDetails: false + } + }; + + render() { + let cardDetails; + if (this.state.showDetails) { + cardDetails = ( +
+ {this.props.description} + +
+ ); + }; + return ( +
+
this.setState({showDetails: !this.state.showDetails}) + }>{this.props.title}
+ {cardDetails} +
+ ); + } +} + +export default Card; diff --git a/app/CheckList.js b/app/CheckList.js new file mode 100644 index 0000000..23cc0ed --- /dev/null +++ b/app/CheckList.js @@ -0,0 +1,21 @@ +import React, { Component } from 'react'; + +class CheckList extends Component { + render() { + let tasks = this.props.tasks.map((task) => ( +
  • + + {task.name} + +
  • + )); + + return ( +
    +
      {tasks}
    +
    + ); + } +} + +export default CheckList; diff --git a/app/KanbanBoard.js b/app/KanbanBoard.js new file mode 100644 index 0000000..20f2b07 --- /dev/null +++ b/app/KanbanBoard.js @@ -0,0 +1,22 @@ +import React, { Component } from 'react'; +import List from './List'; + +class KanbanBoard extends Component { + render(){ + return ( +
    + card.status === "todo")} /> + card.status === "in-progress")} /> + card.status === "done")} /> +
    + ); + } +}; + +export default KanbanBoard; diff --git a/app/List.js b/app/List.js new file mode 100644 index 0000000..7321fde --- /dev/null +++ b/app/List.js @@ -0,0 +1,22 @@ +import React, { Component } from 'react'; +import Card from './Card'; + +class List extends Component { + render() { + var cards = this.props.cards.map((card) => { + return + }); + + return ( +
    +

    {this.props.title}

    + {cards} +
    + ); + } +}; + +export default List; diff --git a/package.json b/package.json new file mode 100755 index 0000000..9c86840 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "kanban-app", + "version": "0.1.0", + "description": "Pro React sample kanban app project", + "author": "Cássio Zen", + "license": "MIT", + "scripts": { + "start": "webpack-dev-server --progress", + "build": "NODE_ENV=production webpack -p --progress --colors" + }, + "devDependencies": { + "babel-core": "~6.7.*", + "babel-loader": "~6.2.*", + "babel-preset-es2015": "~6.6.*", + "babel-preset-react": "~6.5.*", + "webpack": "~1.12.*", + "webpack-dev-server": "~1.14.*" + }, + "dependencies": { + "react": "^15.0.0", + "react-dom": "^15.0.0" + } +} diff --git a/public/index.html b/public/index.html new file mode 100755 index 0000000..4e1565a --- /dev/null +++ b/public/index.html @@ -0,0 +1,13 @@ + + + + + Pro-React Kanban + + + +
    +
    + + + diff --git a/public/styles.css b/public/styles.css new file mode 100755 index 0000000..b934ab3 --- /dev/null +++ b/public/styles.css @@ -0,0 +1,92 @@ +*{ + box-sizing: border-box; +} + +html,body,#root { + height:100%; + margin: 0; + padding: 0; +} + +body { + background: #eee; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +h1{ + font-weight: 200; + color: #3b414c; + font-size: 20px; +} + +ul { + list-style-type: none; + padding: 0; + margin: 0; +} + +.app { + white-space: nowrap; + height:100%; +} + +.list { + position: relative; + display: inline-block; + vertical-align: top; + white-space: normal; + height: 100%; + width: 33%; + padding: 0 20px; + overflow: auto; +} + +.list:not(:last-child):after{ + content: ""; + position: absolute; + top: 0; + right: 0; + width: 1px; + height: 99%; + background: linear-gradient(to bottom, #eee 0%, #ccc 50%, #eee 100%) fixed; +} + +.card { + position: relative; + z-index: 1; + background: #fff; + width: 100%; + padding: 10px 10px 10px 15px; + margin: 0 0 10px 0; + overflow: auto; + border: 1px solid #e5e5df; + border-radius: 3px; + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} + +.card__title { + font-weight: bold; + border-bottom: solid 5px transparent; +} + +.card__title:before { + display: inline-block; + width: 1em; + content: '▸'; +} + +.card__title--is-open:before { + content: '▾'; +} + +.checklist__task:first-child { + margin-top: 10px; + padding-top: 10px; + border-top: dashed 1px #ddd; +} + +.checklist__task--remove:after{ + display: inline-block; + color: #d66; + content: "✖"; +} diff --git a/webpack.config.js b/webpack.config.js new file mode 100755 index 0000000..4c490a0 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,45 @@ +var webpack = require('webpack'); + +/* + * Default webpack configuration for development + */ +var config = { + devtool: 'eval-source-map', + entry: __dirname + "/app/App.js", + output: { + path: __dirname + "/public", + filename: "bundle.js" + }, + module: { + loaders: [{ + test: /\.jsx?$/, + exclude: /node_modules/, + loader: 'babel', + query: { + presets: ['es2015','react'] + } + }] + }, + devServer: { + contentBase: "./public", + colors: true, + historyApiFallback: true, + inline: true + }, +} + +/* + * If bundling for production, optimize output + */ +if (process.env.NODE_ENV === 'production') { + config.devtool = false; + config.plugins = [ + new webpack.optimize.OccurenceOrderPlugin(), + new webpack.optimize.UglifyJsPlugin({comments: false}), + new webpack.DefinePlugin({ + 'process.env': {NODE_ENV: JSON.stringify('production')} + }) + ]; +}; + +module.exports = config;