set up demo, exercise, final folders

This commit is contained in:
Micah Godbolt 2019-02-21 21:49:50 -08:00
Родитель 37598e5812
Коммит 88cb5ddff3
57 изменённых файлов: 869 добавлений и 30 удалений

Просмотреть файл

Просмотреть файл

@ -1,4 +1,4 @@
import React from "react";
import ReactDOM from "react-dom";
import { TodoApp } from "./App";
ReactDOM.render(<TodoApp />, document.getElementById("app"));
import React from 'react';
import ReactDOM from 'react-dom';
import { TodoApp } from './TodoApp';
ReactDOM.render(<TodoApp />, document.getElementById('app'));

Просмотреть файл

@ -1,13 +1,20 @@
already done
itemCount filtering
## demo
demo
add state
add state to AppTodo
pass to header and list
add filter class stuff
controlled components (header) with consolelog
exercise
### header
- pull filter from props
- update buttons with classNames for active
- Add value/onChange to input
### TodoList
- write map to loop through items, pass key and todos
## exercise
update footer to include todos
add item count and item(s)
update ListItem, pull in props, use label/completed already passed in

9
step1-06/demo/index.html Normal file
Просмотреть файл

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="./src/style.css" />
<body>
<div id="app"></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,16 @@
import React from 'react';
import { TodoFooter } from './components/TodoFooter';
import { TodoHeader } from './components/TodoHeader';
import { TodoList } from './components/TodoList';
export class TodoApp extends React.Component {
render() {
return (
<div>
<TodoHeader />
<TodoList />
<TodoFooter />
</div>
);
}
}

Просмотреть файл

@ -0,0 +1,11 @@
import React from 'react';
export const TodoFooter = (props: any) => {
const itemCount = Object.keys(props.todos).filter(id => !props.todos[id].completed).length;
return (
<footer>
<span>4 items left</span>
<button className="submit">Clear Completed</button>
</footer>
);
};

Просмотреть файл

@ -0,0 +1,29 @@
import React from 'react';
export class TodoHeader extends React.Component<any, any> {
constructor(props) {
super(props);
this.state = { labelInput: '' };
}
render() {
return (
<header>
<h1>todos</h1>
<div className="addTodo">
<input className="textfield" placeholder="add todo" />
<button className="submit">Add</button>
</div>
<nav className="filter">
<button className="active">all</button>
<button>active</button>
<button>completed</button>
</nav>
</header>
);
}
_onChange = evt => {
this.setState({ labelInput: evt.target.value });
};
}

Просмотреть файл

@ -0,0 +1,20 @@
import React from 'react';
import { TodoListItem } from './TodoListItem';
export class TodoList extends React.Component<any, any> {
render() {
const { filter, todos } = this.props;
const filteredTodos = Object.keys(todos).filter(id => {
return filter === 'all' || (filter === 'completed' && todos[id].completed) || (filter === 'active' && !todos[id].completed);
});
return (
<ul className="todos">
<TodoListItem />
<TodoListItem />
<TodoListItem />
<TodoListItem />
</ul>
);
}
}

Просмотреть файл

@ -0,0 +1,13 @@
import React from "react";
export class TodoListItem extends React.Component {
render() {
return (
<li className="todo">
<label>
<input type="checkbox" /> Todo 1
</label>
</li>
);
}
}

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="./src/style.css" />
<body>
<div id="app"></div>
</body>
</html>

Просмотреть файл

Просмотреть файл

@ -0,0 +1,11 @@
import React from 'react';
export const TodoFooter = (props: any) => {
const itemCount = Object.keys(props.todos).filter(id => !props.todos[id].completed).length;
return (
<footer>
<span>4 items left</span>
<button className="submit">Clear Completed</button>
</footer>
);
};

Просмотреть файл

@ -0,0 +1,30 @@
import React from 'react';
export class TodoHeader extends React.Component<any, any> {
constructor(props) {
super(props);
this.state = { labelInput: '' };
}
render() {
const { filter } = this.props;
return (
<header>
<h1>todos</h1>
<div className="addTodo">
<input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" />
<button className="submit">Add</button>
</div>
<nav className="filter">
<button className={filter == 'all' ? 'active' : ''}>all</button>
<button className={filter == 'active' ? 'active' : ''}>active</button>
<button className={filter == 'completed' ? 'active' : ''}>completed</button>
</nav>
</header>
);
}
_onChange = evt => {
this.setState({ labelInput: evt.target.value });
};
}

Просмотреть файл

@ -0,0 +1,13 @@
import React from 'react';
export class TodoListItem extends React.Component<any, any> {
render() {
return (
<li className="todo">
<label>
<input type="checkbox" /> Todo 1
</label>
</li>
);
}
}

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="./src/style.css" />
<body>
<div id="app"></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,41 @@
import React from 'react';
import { TodoFooter } from './components/TodoFooter';
import { TodoHeader } from './components/TodoHeader';
import { TodoList } from './components/TodoList';
export class TodoApp extends React.Component<any, any> {
constructor(props) {
super(props);
this.state = {
todos: {
'04': {
label: 'Todo 4',
completed: true
},
'03': {
label: 'Todo 3',
completed: false
},
'02': {
label: 'Todo 2',
completed: false
},
'01': {
label: 'Todo 1',
completed: false
}
},
filter: 'all'
};
}
render() {
const { filter, todos } = this.state;
return (
<div>
<TodoHeader filter={filter} />
<TodoList todos={todos} filter={filter} />
<TodoFooter todos={todos} />
</div>
);
}
}

Просмотреть файл

@ -0,0 +1,19 @@
import React from 'react';
import { TodoListItem } from './TodoListItem';
export class TodoList extends React.Component<any, any> {
render() {
const { filter, todos } = this.props;
const filteredTodos = Object.keys(todos).filter(id => {
return filter === 'all' || (filter === 'completed' && todos[id].completed) || (filter === 'active' && !todos[id].completed);
});
return (
<ul className="todos">
{filteredTodos.map(id => (
<TodoListItem key={id} {...todos[id]} />
))}
</ul>
);
}
}

Просмотреть файл

@ -0,0 +1,4 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { TodoApp } from './TodoApp';
ReactDOM.render(<TodoApp />, document.getElementById('app'));

Просмотреть файл

@ -0,0 +1,49 @@
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
width: 400px;
margin: 20px auto;
}
h1 {
text-align: center;
}
.addTodo {
display: flex;
}
.textfield {
flex-grow: 1;
margin-right: 10px;
}
.submit {
border: none;
padding: 5px 10px;
}
.filter {
margin: 10px 0 0;
}
.filter button {
background: transparent;
border: none;
}
.filter .active {
border-bottom: 2px solid blue;
}
.todos {
list-style: none;
padding: 0;
}
footer {
display: flex;
}
footer span {
flex-grow: 1;
}

Просмотреть файл

@ -1,9 +1,15 @@
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="./src/style.css" />
<body>
<div id="app"></div>
<head>
<link rel="stylesheet" href="../assets/shared.css" />
<link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/9.6.1/css/fabric.min.css" />
</head>
<body class="ms-Fabric">
<div class="Container">
<ul class="Tiles">
<li class="Tile"><a href="./demo/index.html" class="Tile-link">Demo Start</a></li>
<li class="Tile"><a href="./final/index.html" class="Tile-link">Final</a></li>
</ul>
</div>
</body>
</html>

Просмотреть файл

@ -5,14 +5,33 @@ TodoApp methods
filteredTodos in List
demo
## app
Add Types to TodoApp
change 'filter' value
Types in List
pass complete to List - show types, change complete to boolean/, filter
change 'filter' state value to demonstrate
## List (open list next to app)
Demo TodoApp.types
Add Types in List
## App
Back to App, add complete={this.\_complete} to Todolist - show types, change complete to 'false', filter
## List
add complete, pass to item (prop drilling)
## List Item (move List Item into App window)
TodoListItemProps, extend, id, complete (possible abstraction)
Demo how you can't add random things to TodoListItem or this.props now
add complete to List item
add props, add complete to List item
## List
Demo how you can't add random things to TodoListItem or item's this.props now
exercise
@ -20,4 +39,5 @@ Add types to footer
Add onClick to button
Add types to header
Add setFilter to filter buttons
add 'addTodo' to onAdd function
write onAdd function
place onAdd to submit button

7
step1-07/demo/index.html Normal file
Просмотреть файл

@ -0,0 +1,7 @@
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="./src/style.css" />
<body>
<div id="app"></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,69 @@
import React from 'react';
import { TodoFooter } from './components/TodoFooter';
import { TodoHeader } from './components/TodoHeader';
import { TodoList } from './components/TodoList';
import { Todos, FilterTypes } from './TodoApp.types';
let index = 0;
export class TodoApp extends React.Component<any, any> {
constructor(props) {
super(props);
this.state = {
todos: {},
filter: 'all'
};
}
render() {
const { filter, todos } = this.state;
return (
<div>
<TodoHeader addTodo={this._addTodo} setFilter={this._setFilter} filter={filter} />
<TodoList complete={this._complete} todos={todos} filter={filter} />
<TodoFooter clear={this._clear} todos={todos} />
</div>
);
}
// business logic
private _addTodo = label => {
const { todos } = this.state;
const id = index++;
this.setState({
todos: { ...todos, [id]: { label, completed: false } }
});
};
private _complete = id => {
const newTodos = { ...this.state.todos };
newTodos[id].completed = !newTodos[id].completed;
this.setState({
todos: newTodos
});
};
private _clear = () => {
const { todos } = this.state;
const newTodos = {};
Object.keys(this.state.todos).forEach(id => {
if (!todos[id].completed) {
newTodos[id] = todos[id];
}
});
this.setState({
todos: newTodos
});
};
private _setFilter = filter => {
this.setState({
filter: filter
});
};
}

Просмотреть файл

Просмотреть файл

@ -0,0 +1,14 @@
import React from 'react';
import { Todos } from '../TodoApp.types';
export const TodoFooter = (props: any) => {
const itemCount = Object.keys(props.todos).filter(id => !props.todos[id].completed).length;
return (
<footer>
<span>
{itemCount} item{itemCount > 1 ? 's' : ''} left
</span>
<button className="submit">Clear Completed</button>
</footer>
);
};

Просмотреть файл

@ -0,0 +1,31 @@
import React from 'react';
import { FilterTypes } from '../TodoApp.types';
export class TodoHeader extends React.Component<any, any> {
constructor(props) {
super(props);
this.state = { labelInput: '' };
}
render() {
const { filter } = this.props;
return (
<header>
<h1>todos</h1>
<div className="addTodo">
<input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" />
<button className="submit">Add</button>
</div>
<nav className="filter">
<button className={filter == 'all' ? 'active' : ''}>all</button>
<button className={filter == 'active' ? 'active' : ''}>active</button>
<button className={filter == 'completed' ? 'active' : ''}>completed</button>
</nav>
</header>
);
}
_onChange = evt => {
this.setState({ labelInput: evt.target.value });
};
}

Просмотреть файл

@ -0,0 +1,21 @@
import React from 'react';
import { TodoListItem } from './TodoListItem';
import { FilterTypes, Todos } from '../TodoApp.types';
export class TodoList extends React.Component<any, any> {
render() {
const { filter, todos, complete } = this.props;
const filteredTodos = Object.keys(todos).filter(id => {
return filter === 'all' || (filter === 'completed' && todos[id].completed) || (filter === 'active' && !todos[id].completed);
});
return (
<ul className="todos">
{filteredTodos.map(id => (
<TodoListItem key={id} id={id} complete={complete} {...todos[id]} />
))}
</ul>
);
}
}

Просмотреть файл

@ -0,0 +1,16 @@
import React from 'react';
import { TodoItem } from '../TodoApp.types';
export class TodoListItem extends React.Component<any, any> {
render() {
const { label, completed } = this.props;
return (
<li className="todo">
<label>
<input type="checkbox" checked={completed} /> {label}
</label>
</li>
);
}
}

Просмотреть файл

@ -0,0 +1,4 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { TodoApp } from './TodoApp';
ReactDOM.render(<TodoApp />, document.getElementById('app'));

Просмотреть файл

@ -0,0 +1,49 @@
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
width: 400px;
margin: 20px auto;
}
h1 {
text-align: center;
}
.addTodo {
display: flex;
}
.textfield {
flex-grow: 1;
margin-right: 10px;
}
.submit {
border: none;
padding: 5px 10px;
}
.filter {
margin: 10px 0 0;
}
.filter button {
background: transparent;
border: none;
}
.filter .active {
border-bottom: 2px solid blue;
}
.todos {
list-style: none;
padding: 0;
}
footer {
display: flex;
}
footer span {
flex-grow: 1;
}

Просмотреть файл

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="./src/style.css" />
<body>
<div id="app"></div>
</body>
</html>

Просмотреть файл

Просмотреть файл

@ -0,0 +1,10 @@
export type FilterTypes = 'all' | 'active' | 'completed';
export interface TodoItem {
label: string;
completed: boolean;
}
export interface Todos {
[id: string]: TodoItem;
}

Просмотреть файл

@ -0,0 +1,14 @@
import React from 'react';
import { Todos } from '../TodoApp.types';
export const TodoFooter = props => {
const itemCount = Object.keys(props.todos).filter(id => !props.todos[id].completed).length;
return (
<footer>
<span>
{itemCount} item{itemCount > 1 ? 's' : ''} left
</span>
<button className="submit">Clear Completed</button>
</footer>
);
};

Просмотреть файл

@ -0,0 +1,31 @@
import React from 'react';
import { FilterTypes } from '../TodoApp.types';
export class TodoHeader extends React.Component<any, any> {
constructor(props) {
super(props);
this.state = { labelInput: '' };
}
render() {
const { filter } = this.props;
return (
<header>
<h1>todos</h1>
<div className="addTodo">
<input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" />
<button className="submit">Add</button>
</div>
<nav className="filter">
<button className={filter == 'all' ? 'active' : ''}>all</button>
<button className={filter == 'active' ? 'active' : ''}>active</button>
<button className={filter == 'completed' ? 'active' : ''}>completed</button>
</nav>
</header>
);
}
_onChange = evt => {
this.setState({ labelInput: evt.target.value });
};
}

Просмотреть файл

@ -0,0 +1,4 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { TodoApp } from './TodoApp';
ReactDOM.render(<TodoApp />, document.getElementById('app'));

Просмотреть файл

@ -0,0 +1,49 @@
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
width: 400px;
margin: 20px auto;
}
h1 {
text-align: center;
}
.addTodo {
display: flex;
}
.textfield {
flex-grow: 1;
margin-right: 10px;
}
.submit {
border: none;
padding: 5px 10px;
}
.filter {
margin: 10px 0 0;
}
.filter button {
background: transparent;
border: none;
}
.filter .active {
border-bottom: 2px solid blue;
}
.todos {
list-style: none;
padding: 0;
}
footer {
display: flex;
}
footer span {
flex-grow: 1;
}

Просмотреть файл

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="./src/style.css" />
<body>
<div id="app"></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,69 @@
import React from 'react';
import { TodoFooter } from './components/TodoFooter';
import { TodoHeader } from './components/TodoHeader';
import { TodoList } from './components/TodoList';
import { Todos, FilterTypes } from './TodoApp.types';
let index = 0;
export class TodoApp extends React.Component<any, { todos: Todos; filter: FilterTypes }> {
constructor(props) {
super(props);
this.state = {
todos: {},
filter: 'all'
};
}
render() {
const { filter, todos } = this.state;
return (
<div>
<TodoHeader addTodo={this._addTodo} setFilter={this._setFilter} filter={filter} />
<TodoList complete={this._complete} todos={todos} filter={filter} />
<TodoFooter clear={this._clear} todos={todos} />
</div>
);
}
// business logic
private _addTodo = label => {
const { todos } = this.state;
const id = index++;
this.setState({
todos: { ...todos, [id]: { label, completed: false } }
});
};
private _complete = id => {
const newTodos = { ...this.state.todos };
newTodos[id].completed = !newTodos[id].completed;
this.setState({
todos: newTodos
});
};
private _clear = () => {
const { todos } = this.state;
const newTodos = {};
Object.keys(this.state.todos).forEach(id => {
if (!todos[id].completed) {
newTodos[id] = todos[id];
}
});
this.setState({
todos: newTodos
});
};
private _setFilter = filter => {
this.setState({
filter: filter
});
};
}

Просмотреть файл

@ -0,0 +1,10 @@
export type FilterTypes = 'all' | 'active' | 'completed';
export interface TodoItem {
label: string;
completed: boolean;
}
export interface Todos {
[id: string]: TodoItem;
}

Просмотреть файл

@ -0,0 +1,27 @@
import React from 'react';
import { TodoListItem } from './TodoListItem';
import { FilterTypes, Todos } from '../TodoApp.types';
interface TodoListProps {
complete: (id: string) => void;
todos: Todos;
filter: FilterTypes;
}
export class TodoList extends React.Component<TodoListProps, any> {
render() {
const { filter, todos, complete } = this.props;
const filteredTodos = Object.keys(todos).filter(id => {
return filter === 'all' || (filter === 'completed' && todos[id].completed) || (filter === 'active' && !todos[id].completed);
});
return (
<ul className="todos">
{filteredTodos.map(id => (
<TodoListItem key={id} id={id} complete={complete} {...todos[id]} />
))}
</ul>
);
}
}

Просмотреть файл

@ -0,0 +1,21 @@
import React from 'react';
import { TodoItem } from '../TodoApp.types';
interface TodoListItemProps extends TodoItem {
id: string;
complete: (id: string) => void;
}
export class TodoListItem extends React.Component<TodoListItemProps, any> {
render() {
const { label, completed, complete, id } = this.props;
return (
<li className="todo">
<label>
<input type="checkbox" checked={completed} onChange={() => complete(id)} /> {label}
</label>
</li>
);
}
}

Просмотреть файл

@ -0,0 +1,4 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { TodoApp } from './TodoApp';
ReactDOM.render(<TodoApp />, document.getElementById('app'));

Просмотреть файл

@ -0,0 +1,49 @@
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
width: 400px;
margin: 20px auto;
}
h1 {
text-align: center;
}
.addTodo {
display: flex;
}
.textfield {
flex-grow: 1;
margin-right: 10px;
}
.submit {
border: none;
padding: 5px 10px;
}
.filter {
margin: 10px 0 0;
}
.filter button {
background: transparent;
border: none;
}
.filter .active {
border-bottom: 2px solid blue;
}
.todos {
list-style: none;
padding: 0;
}
footer {
display: flex;
}
footer span {
flex-grow: 1;
}

Просмотреть файл

@ -1,9 +1,15 @@
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="./src/style.css" />
<body>
<div id="app"></div>
<head>
<link rel="stylesheet" href="../assets/shared.css" />
<link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/9.6.1/css/fabric.min.css" />
</head>
<body class="ms-Fabric">
<div class="Container">
<ul class="Tiles">
<li class="Tile"><a href="./demo/index.html" class="Tile-link">Demo Start</a></li>
<li class="Tile"><a href="./final/index.html" class="Tile-link">Final</a></li>
</ul>
</div>
</body>
</html>