Skip to content

Commit f15a508

Browse files
committed
Finish connecting redux to react, also build UI
1 parent 0e2accd commit f15a508

File tree

18 files changed

+555
-123
lines changed

18 files changed

+555
-123
lines changed

todomvc/.babelrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"presets": [
33
"es2015",
4-
"react"
4+
"react",
5+
"stage-0"
56
]
67
}

todomvc/app/actions/todo.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,6 @@ export function toggleTodo(todoID) {
3939
}
4040
}
4141

42-
export function completeAllTodos() {
43-
return {
44-
type: Action.COMPLETE_ALL_TODOS,
45-
}
46-
}
47-
4842
export function deleteTodo(todoID) {
4943
return {
5044
type: Action.DELETE_TODO,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
.container {
2+
padding: 15px 25px 15px 25px;
3+
border-top: 1px solid rgba(0,0,0,0.1);
4+
color: rgba(0,0,0,0.3);
5+
font-size: 0.9rem;
6+
}
7+
8+
.active {
9+
color: #fc6c85;
10+
}
11+
12+
.itemleft {
13+
margin-right: 60px;
14+
}
15+
16+
.col {
17+
display: inline-block;
18+
}
19+
20+
.spacing {
21+
margin-right: 10px;
22+
}
23+
24+
.alignright {
25+
float: right;
26+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import React, { Component, PropTypes } from 'react';
2+
import classnames from 'classnames';
3+
import styles from './Footer.css';
4+
import * as VisibilityFilterActions from '../../actions/visibility-filter';
5+
6+
export default class Footer extends Component {
7+
8+
constructor(props) {
9+
super(props);
10+
11+
this.state = {
12+
showAll: true,
13+
showUnCompleted: false,
14+
showCompleted: false
15+
}
16+
}
17+
18+
handleSetVisibility = (filter) => {
19+
20+
console.log('filter: ', filter);
21+
22+
switch (filter) {
23+
24+
case VisibilityFilterActions.VisibilityFilter.SHOW_ALL_TODOS:
25+
this.setState({
26+
showAll: true,
27+
showUnCompleted: false,
28+
showCompleted: false
29+
});
30+
this.props.onShowAll();
31+
break;
32+
33+
case VisibilityFilterActions.VisibilityFilter.SHOW_COMPLETED_TODOS:
34+
this.setState({
35+
showAll: false,
36+
showUnCompleted: false,
37+
showCompleted: true
38+
});
39+
this.props.onShowCompleted();
40+
break;
41+
42+
case VisibilityFilterActions.VisibilityFilter.SHOW_UNCOMPLETED_TODOS:
43+
this.setState({
44+
showAll: false,
45+
showUnCompleted: true,
46+
showCompleted: false
47+
});
48+
this.props.onShowUnCompleted();
49+
break;
50+
51+
default:
52+
this.setState({
53+
showAll: true,
54+
showUnCompleted: false,
55+
showCompleted: false
56+
});
57+
this.props.onShowAll();
58+
break;
59+
}
60+
}
61+
62+
render() {
63+
64+
return (
65+
<div className={classnames(styles.row, styles.container)}>
66+
67+
<span className={styles.itemleft}>{this.props.activeCount} items left</span>
68+
69+
<div className={styles.col}>
70+
<span className={classnames(styles.spacing, {[`${styles.active}`]: this.state.showAll})} onClick={() => this.handleSetVisibility(VisibilityFilterActions.VisibilityFilter.SHOW_ALL_TODOS)}>All</span>
71+
<span className={classnames(styles.spacing, {[`${styles.active}`]: this.state.showUnCompleted})} onClick={() => this.handleSetVisibility(VisibilityFilterActions.VisibilityFilter.SHOW_UNCOMPLETED_TODOS)}>Active</span>
72+
<span className={classnames({[`${styles.active}`]: this.state.showCompleted})} onClick={() => this.handleSetVisibility(VisibilityFilterActions.VisibilityFilter.SHOW_COMPLETED_TODOS)}>Completed</span>
73+
</div>
74+
75+
<div className={classnames(styles.col, styles.alignright)}>
76+
<span onClick={this.props.onClearCompleted}>Clear completed</span>
77+
</div>
78+
</div>
79+
)
80+
}
81+
}
82+
83+
Footer.propTypes = {
84+
activeCount: PropTypes.number.isRequired,
85+
onShowAll: PropTypes.func.isRequired,
86+
onShowCompleted: PropTypes.func.isRequired,
87+
onShowUnCompleted: PropTypes.func.isRequired,
88+
onClearCompleted: PropTypes.func.isRequired
89+
}
90+
91+

todomvc/app/components/Todo/Todo.css

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/* simple grid system */
2+
.row {
3+
width: 100%;
4+
box-sizing: border-box;
5+
}
6+
7+
.row:after {
8+
content: "";
9+
clear: both;
10+
display: block;
11+
}
12+
13+
.col10 {
14+
width: 10%;
15+
float: left;
16+
box-sizing: border-box;
17+
}
18+
19+
.col80 {
20+
width: 80%;
21+
float: left;
22+
box-sizing: border-box;
23+
}
24+
25+
.container {
26+
padding: 25px;
27+
border-top: 1px solid rgba(0,0,0,0.1);
28+
}
29+
30+
.circle {
31+
width: 23px;
32+
height: 23px;
33+
border-radius: 50%;
34+
}
35+
36+
.circle.hollow {
37+
border: 1px solid rgba(0,0,0,0.1);
38+
}
39+
40+
.circle.solid {
41+
background-color: #4ce092;
42+
text-decoration: line-through;
43+
transition: background-color 0.2s;
44+
}
45+
46+
.text {
47+
font-size: 1.2rem;
48+
line-height: 25px;
49+
white-space: pre-line;
50+
word-break: break-all;
51+
vertical-align: middle;
52+
color: rgba(0,0,0,0.5);
53+
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
54+
}
55+
56+
.text.linethrough {
57+
text-decoration: line-through;
58+
font-style: italic;
59+
color: rgba(0,0,0,0.2);
60+
transition: text-decoration 0.4s;
61+
}
62+
63+
.delete {
64+
display: none;
65+
width: 25px;
66+
height: 25px;
67+
font-size: 25px;
68+
line-height: 12px;
69+
color: #fd9eae;
70+
background: none;
71+
border: none;
72+
float: right;
73+
transition: color 0.2s ease-out;
74+
}
75+
76+
.delete:hover {
77+
color: #fc6c85;
78+
}
79+
80+
.delete:after {
81+
content: '×';
82+
}
83+
84+
.container:hover .delete {
85+
display: block;
86+
}

todomvc/app/components/Todo/Todo.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import React, { Component, PropTypes } from 'react';
2+
import classnames from 'classnames';
3+
import styles from './Todo.css';
4+
import TodoInputText from '../TodoInputText/TodoInputText';
5+
6+
export default class Todo extends React.Component {
7+
8+
/* we can init state here */
9+
constructor(props) {
10+
super(props);
11+
12+
this.state = { editing: false };
13+
14+
/**
15+
* Since we use es6+ class syntax, we need to manually bind this method to the component instance.
16+
* e.g. this.handleDoubleClick = this.handleDoubleClick.bind(this);
17+
* But if we use es6+ arrow function syntax, we don't need to bind 'this'. It already binds it for us.
18+
*/
19+
20+
}
21+
22+
handleDoubleClick = (e) => {
23+
24+
this.setState({ editing: true });
25+
}
26+
27+
handleSave = (text) => {
28+
29+
this.props.onEdit(this.props.id, text);
30+
31+
this.setState({ editing: false });
32+
}
33+
34+
render() {
35+
36+
var element;
37+
38+
if (this.state.editing)
39+
element = (
40+
<TodoInputText text={this.props.text} onSave={text => this.handleSave(text)} />
41+
)
42+
else
43+
element = (
44+
<div className={classnames(styles.row, styles.container)}>
45+
46+
<div className={styles.col10}>
47+
<div className={
48+
classnames(
49+
styles.circle,
50+
{
51+
[`${styles.hollow}`]: !this.props.completed,
52+
[`${styles.solid}`]: this.props.completed
53+
}
54+
)}
55+
onClick={this.props.onToggle}>
56+
</div>
57+
</div>
58+
59+
<div className={styles.col80}>
60+
<div className={
61+
classnames(
62+
styles.text,
63+
{
64+
[`${styles.linethrough}`]: this.props.completed
65+
}
66+
)}
67+
onDoubleClick={e => this.handleDoubleClick(e)}>
68+
{this.props.text}
69+
</div>
70+
</div>
71+
72+
<div className={styles.col10}>
73+
<button className={styles.delete} onClick={this.props.onDelete} />
74+
</div>
75+
76+
</div>
77+
)
78+
79+
return element;
80+
}
81+
}
82+
83+
Todo.propTypes = {
84+
id: PropTypes.number.isRequired,
85+
text: PropTypes.string.isRequired,
86+
completed: PropTypes.bool.isRequired,
87+
onToggle: PropTypes.func.isRequired,
88+
onEdit: PropTypes.func.isRequired,
89+
onDelete: PropTypes.func.isRequired
90+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
.input {
2+
width: 100%;
3+
padding: 25px;
4+
border: none;
5+
box-sizing: border-box;
6+
background-color: white;
7+
color: rgba(0,0,0,0.5);
8+
font-size: 1.2rem;
9+
border-top: 1px solid rgba(0,0,0,0.1);
10+
}
11+
12+
.input:focus {
13+
outline: 0;
14+
}
15+
16+
.input::-webkit-input-placeholder {
17+
color: rgba(0,0,0,0.2);
18+
font-style: italic;
19+
}
20+
21+
.input:-moz-placeholder {
22+
/* FF 4-18 */
23+
color: rgba(0,0,0,0.2);
24+
font-style: italic;
25+
}
26+
27+
.input::-moz-placeholder {
28+
/* FF 19+ */
29+
color: rgba(0,0,0,0.2);
30+
font-style: italic;
31+
}
32+
33+
.input:-ms-input-placeholder {
34+
/* IE 10+ */
35+
color: rgba(0,0,0,0.2);
36+
font-style: italic;
37+
}

0 commit comments

Comments
 (0)