Merge branch 'master' of github.com:kenotron/bootcamp

This commit is contained in:
Ken
2019-02-21 15:19:11 -08:00
62 changed files with 906 additions and 129 deletions

12
package-lock.json generated
View File

@@ -3817,6 +3817,7 @@
"version": "2.3.5", "version": "2.3.5",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@@ -3835,6 +3836,7 @@
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@@ -3928,6 +3930,7 @@
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@@ -4013,7 +4016,8 @@
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@@ -4113,12 +4117,14 @@
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.3", "version": "3.0.3",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
} }
} }
}, },

View File

@@ -2,8 +2,12 @@
## Demo ## Demo
Scaffold out page Write html tag down to ul > li, footer
add CSS link
Add active styles, describe specificity
## Exercise ## Exercise
Add and style footer Update list item to match (already styled)
duplicate 3 more times
Add and style footer content

1
step1-02/demo/index.html Normal file
View File

@@ -0,0 +1 @@
<!DOCTYPE html>

37
step1-02/demo/style.css Normal file
View File

@@ -0,0 +1,37 @@
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;
}
.todos {
list-style: none;
padding: 0;
}

View File

@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<header>
<h1>todos</h1>
<div class="addTodo">
<input class="textfield" placeholder="add todo" />
<button class="submit">Add</button>
</div>
<nav class="filter">
<button class="active">all</button>
<button>active</button>
<button>completed</button>
</nav>
</header>
<main>
<ul class="todos">
<li>Todo 1</li>
</ul>
</main>
</body>
</html>

View File

@@ -0,0 +1,41 @@
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;
}

View File

@@ -6,7 +6,10 @@
<body> <body>
<header> <header>
<h1>todos</h1> <h1>todos</h1>
<div class="addTodo"><input class="textfield" placeholder="add todo" /><button class="submit">Add</button></div> <div class="addTodo">
<input class="textfield" placeholder="add todo" />
<button class="submit">Add</button>
</div>
<nav class="filter"> <nav class="filter">
<button class="active">all</button> <button class="active">all</button>
<button>active</button> <button>active</button>

View File

@@ -0,0 +1,16 @@
<html>
<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="./exercise/index.html" class="Tile-link">Exercise Start</a></li>
<li class="Tile"><a href="./final/index.html" class="Tile-link">Final</a></li>
</ul>
</div>
</body>
</html>

View File

@@ -9,10 +9,11 @@ already done
Walk through 'addTodo' Walk through 'addTodo'
attach addTodo to button attach addTodo to button
write clearInput/add to addTodo write clearInput
write updateRemaining write updateRemaining
## Exercise ## Exercise
add filter to filter buttons
write clearCompleted write clearCompleted
add to footer button add to footer button

70
step1-03/demo/index.html Normal file
View File

@@ -0,0 +1,70 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<header>
<h1>todos</h1>
<div class="addTodo">
<input class="textfield" placeholder="add todo" />
<button class="submit add">Add</button>
</div>
<nav class="filter">
<button class="active">all</button>
<button>active</button>
<button>completed</button>
</nav>
</header>
<ul class="todos">
<li class="todo">
<label><input type="checkbox" /> <span class="title"> Todo 1 </span></label>
</li>
<li class="todo">
<label><input type="checkbox" /> <span class="title"> Todo 2 </span></label>
</li>
<li class="todo">
<label><input type="checkbox" /> <span class="title"> Todo 3 </span></label>
</li>
<li class="todo">
<label><input type="checkbox" /> <span class="title"> Todo 4 </span></label>
</li>
</ul>
<footer>
<span><span class="remaining">4</span> items left</span>
<button class="submit">Clear Completed</button>
</footer>
</body>
<script type="text/javascript">
function getTodoText() {
return document.querySelector('.textfield').value;
}
function addTodo() {
const todo = document.querySelector('.todo');
const newTodo = todo.cloneNode(true);
newTodo.querySelector('.title').innerText = getTodoText();
todo.parentElement.insertBefore(newTodo, todo);
// clearInput();
// updateRemaining();
}
function filter(scope, button) {
document.querySelector('.active').classList.remove('active');
button.classList.add('active');
for (let todo of document.querySelectorAll('.todo')) {
const checked = todo.querySelector('input').checked == true;
if (scope == 'all') {
todo.hidden = false;
} else if (scope == 'active') {
todo.hidden = checked;
} else if (scope == 'completed') {
todo.hidden = !checked;
}
}
}
</script>
</html>

View File

@@ -0,0 +1,82 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<header>
<h1>todos</h1>
<div class="addTodo">
<input class="textfield" placeholder="add todo" />
<button onclick="addTodo()" class="submit add">Add</button>
</div>
<nav class="filter">
<button class="active">all</button>
<button>active</button>
<button>completed</button>
</nav>
</header>
<ul class="todos">
<li class="todo">
<label><input type="checkbox" /> <span class="title"> Todo 1 </span></label>
</li>
<li class="todo">
<label><input type="checkbox" /> <span class="title"> Todo 2 </span></label>
</li>
<li class="todo">
<label><input type="checkbox" /> <span class="title"> Todo 3 </span></label>
</li>
<li class="todo">
<label><input type="checkbox" /> <span class="title"> Todo 4 </span></label>
</li>
</ul>
<footer>
<span><span class="remaining">4</span> items left</span>
<button class="submit">Clear Completed</button>
</footer>
</body>
<script type="text/javascript">
function getTodoText() {
return document.querySelector('.textfield').value;
}
function clearInput() {
document.querySelector('.textfield').value = '';
}
function updateRemaining() {
const remaining = document.querySelector('.remaining');
const todos = document.querySelectorAll('.todo').length;
remaining.innerText = todos;
}
function addTodo() {
const todo = document.querySelector('.todo');
const newTodo = todo.cloneNode(true);
newTodo.querySelector('.title').innerText = getTodoText();
todo.parentElement.insertBefore(newTodo, todo);
clearInput();
updateRemaining();
}
// clearCompleted
function filter(scope, button) {
document.querySelector('.active').classList.remove('active');
button.classList.add('active');
for (let todo of document.querySelectorAll('.todo')) {
const checked = todo.querySelector('input').checked == true;
if (scope == 'all') {
todo.hidden = false;
} else if (scope == 'active') {
todo.hidden = checked;
} else if (scope == 'completed') {
todo.hidden = !checked;
}
}
}
</script>
</html>

90
step1-03/final/index.html Normal file
View File

@@ -0,0 +1,90 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<header>
<h1>todos</h1>
<div class="addTodo">
<input class="textfield" placeholder="add todo" />
<button onclick="addTodo()" class="submit add">Add</button>
</div>
<nav class="filter">
<button onclick="filter('all', this)" class="active">all</button>
<button onclick="filter('active', this)">active</button>
<button onclick="filter('completed', this)">completed</button>
</nav>
</header>
<ul class="todos">
<li class="todo">
<label><input type="checkbox" /> <span class="title"> Todo 1 </span></label>
</li>
<li class="todo">
<label><input type="checkbox" /> <span class="title"> Todo 2 </span></label>
</li>
<li class="todo">
<label><input type="checkbox" /> <span class="title"> Todo 3 </span></label>
</li>
<li class="todo">
<label><input type="checkbox" /> <span class="title"> Todo 4 </span></label>
</li>
</ul>
<footer>
<span><span class="remaining">4</span> items left</span>
<button onclick="clearCompleted()" class="submit">Clear Completed</button>
</footer>
</body>
<script type="text/javascript">
function getTodoText() {
return document.querySelector('.textfield').value;
}
function clearInput() {
document.querySelector('.textfield').value = '';
}
function updateRemaining() {
const remaining = document.querySelector('.remaining');
const todos = document.querySelectorAll('.todo').length;
remaining.innerText = todos;
}
function addTodo() {
const todo = document.querySelector('.todo');
const newTodo = todo.cloneNode(true);
newTodo.querySelector('.title').innerText = getTodoText();
todo.parentElement.insertBefore(newTodo, todo);
clearInput();
updateRemaining();
}
function clearCompleted() {
const todos = document.querySelectorAll('.todo');
for (let todo of todos) {
if (todo.querySelector('input').checked == true) {
todo.remove();
}
}
updateRemaining();
}
function filter(scope, button) {
document.querySelector('.active').classList.remove('active');
button.classList.add('active');
for (let todo of document.querySelectorAll('.todo')) {
const checked = todo.querySelector('input').checked == true;
if (scope == 'all') {
todo.hidden = false;
} else if (scope == 'active') {
todo.hidden = checked;
} else if (scope == 'completed') {
todo.hidden = !checked;
}
}
}
</script>
</html>

49
step1-03/final/style.css Normal file
View File

@@ -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;
}

View File

@@ -1,90 +1,16 @@
<!DOCTYPE html>
<html> <html>
<head> <head>
<link rel="stylesheet" href="./style.css" /> <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> </head>
<body>
<header>
<h1>todos</h1>
<div class="addTodo">
<input class="textfield" placeholder="add todo" />
<button onclick="addTodo()" class="submit add">Add</button>
</div>
<nav class="filter">
<button onclick="filter('all', this)" class="active">all</button>
<button onclick="filter('active', this)">active</button>
<button onclick="filter('completed', this)">completed</button>
</nav>
</header>
<ul class="todos"> <body class="ms-Fabric">
<li class="todo"> <div class="Container">
<label><input type="checkbox" /> <span class="title"> Todo 1 </span></label> <ul class="Tiles">
</li> <li class="Tile"><a href="./demo/index.html" class="Tile-link">Demo Start</a></li>
<li class="todo"> <li class="Tile"><a href="./exercise/index.html" class="Tile-link">Exercise Start</a></li>
<label><input type="checkbox" /> <span class="title"> Todo 2 </span></label> <li class="Tile"><a href="./final/index.html" class="Tile-link">Final</a></li>
</li> </ul>
<li class="todo"> </div>
<label><input type="checkbox" /> <span class="title"> Todo 3 </span></label>
</li>
<li class="todo">
<label><input type="checkbox" /> <span class="title"> Todo 4 </span></label>
</li>
</ul>
<footer>
<span><span class="remaining">4</span> items left</span>
<button onclick="clearCompleted()" class="button">Clear Completed</button>
</footer>
</body> </body>
<script type="text/javascript">
function getTodoText() {
return document.querySelector('.textfield').value;
}
function clearInput() {
document.querySelector('.textfield').value = '';
}
function updateRemaining() {
const remaining = document.querySelector('.remaining');
const todos = document.querySelectorAll('.todo').length;
remaining.innerText = todos;
}
function addTodo() {
const todo = document.querySelector('.todo');
const newTodo = todo.cloneNode(true);
newTodo.querySelector('.title').innerText = getTodoText();
todo.parentElement.insertBefore(newTodo, todo);
clearInput();
updateRemaining();
}
function clearCompleted() {
const todos = document.querySelectorAll('.todo');
for (let todo of todos) {
if (todo.querySelector('input').checked == true) {
todo.remove();
}
}
updateRemaining();
}
function filter(scope, button) {
document.querySelector('.active').classList.remove('active');
button.classList.add('active');
for (let todo of document.querySelectorAll('.todo')) {
const checked = todo.querySelector('input').checked == true;
if (scope == 'all') {
todo.hidden = false;
} else if (scope == 'active') {
todo.hidden = checked;
} else if (scope == 'completed') {
todo.hidden = !checked;
}
}
}
</script>
</html> </html>

12
step1-04/README.md Normal file
View File

@@ -0,0 +1,12 @@
## React quick demo
already done:
Button.css
scaffold app.tsx (my app)
write index.tsx
write index.html
demo 'hello world'
Write Counter Component with button
Demo Button, import into Component

6
step1-04/demo/index.html Normal file
View File

@@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
<div id="app"></div>
</body>
</html>

View File

@@ -6,7 +6,8 @@ export class App extends React.Component {
return ( return (
<div> <div>
<h2>My App</h2> <h2>My App</h2>
<Counter start={2} /> <Counter text="Chickens" />
<Counter text="Ducks" />
</div> </div>
); );
} }

View File

@@ -1,4 +1,5 @@
.Button { .Button {
display: block;
background: #0078d4; background: #0078d4;
color: white; color: white;
padding: 5px 10px; padding: 5px 10px;

View File

@@ -1,23 +1,25 @@
import React from 'react'; import React from 'react';
import { Button } from './Button'; import { Button } from './Button';
export class Counter extends React.Component<any, any> { export class Counter extends React.Component<{ text: string }, { counter: number }> {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
counter: props.start counter: 0
}; };
} }
render() { render() {
const { counter } = this.state;
const { text } = this.props;
return ( return (
<div> <div>
<span> {this.state.counter} </span> {text}: {counter}
<Button <Button
onClick={() => { onClick={() => {
this.setState({ counter: this.state.counter + 1 }); this.setState({ counter: counter + 1 });
}} }}
> >
Click Me Click
</Button> </Button>
</div> </div>
); );

View File

@@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
<div id="app"></div>
</body>
</html>

View File

@@ -0,0 +1,14 @@
import React from 'react';
import { Counter } from './components/Counter';
export class App extends React.Component {
render() {
return (
<div>
<h2>My App</h2>
<Counter text="Chickens" />
<Counter text="Ducks" />
</div>
);
}
}

View File

@@ -0,0 +1,15 @@
.Button {
display: block;
background: #0078d4;
color: white;
padding: 5px 10px;
outline: none;
border: none;
}
.Button:hover {
background: #005a9e;
}
.Button:active {
background: #004578;
}

View File

@@ -0,0 +1,10 @@
import React from 'react';
import './Button.css';
export const Button = props => {
return (
<button className="Button" onClick={props.onClick}>
{props.children}
</button>
);
};

View File

@@ -0,0 +1,27 @@
import React from 'react';
import { Button } from './Button';
export class Counter extends React.Component<{ text: string }, { counter: number }> {
constructor(props) {
super(props);
this.state = {
counter: 0
};
}
render() {
const { counter } = this.state;
const { text } = this.props;
return (
<div>
{text}: {counter}
<Button
onClick={() => {
this.setState({ counter: counter + 1 });
}}
>
Click
</Button>
</div>
);
}
}

View File

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

View File

@@ -1,8 +1,15 @@
<!DOCTYPE html>
<html> <html>
<body> <head>
<div id="app"></div> <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> </body>
</html> </html>

View File

@@ -1,7 +1,12 @@
start with
style/index/index/failing imports
demo demo
Header Header
ListItem ListItem
exercise exercise
Footer Footer
List List

9
step1-05/demo/index.html Normal file
View File

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

View File

@@ -0,0 +1,9 @@
import React from 'react';
export const TodoFooter = (props: any) => {
return (
<footer>
<p>footer</p>
</footer>
);
};

View File

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

View File

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

View File

@@ -0,0 +1,7 @@
import React from 'react';
export class TodoListItem extends React.Component {
render() {
return <div />;
}
}

View File

@@ -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;
}

View File

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

View File

@@ -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>
);
}
}

View File

@@ -0,0 +1,9 @@
import React from 'react';
export const TodoFooter = (props: any) => {
return (
<footer>
<p>footer</p>
</footer>
);
};

View File

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

View File

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

View File

@@ -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;
}

View File

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

View File

@@ -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>
);
}
}

View File

@@ -0,0 +1,20 @@
import React from 'react';
export class TodoHeader extends React.Component {
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>
);
}
}

View File

@@ -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>
);
}
}

View File

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

View File

@@ -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;
}

View File

@@ -1,9 +1,15 @@
<!DOCTYPE html>
<html> <html>
<link rel="stylesheet" href="./src/style.css" /> <head>
<body> <link rel="stylesheet" href="../assets/shared.css" />
<div id="app"></div> <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> </body>
</html> </html>

View File

@@ -6,6 +6,7 @@ demo
add state add state
pass to header and list pass to header and list
add filter class stuff add filter class stuff
controlled components (header) with consolelog
exercise exercise
update footer to include todos update footer to include todos

View File

@@ -8,7 +8,7 @@ export class TodoHeader extends React.Component<any, any> {
<header> <header>
<h1>todos</h1> <h1>todos</h1>
<div className="addTodo"> <div className="addTodo">
<input className="textfield" placeholder="add todo" /> <input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" />
<button className="submit">Add</button> <button className="submit">Add</button>
</div> </div>
<nav className="filter"> <nav className="filter">
@@ -19,4 +19,12 @@ export class TodoHeader extends React.Component<any, any> {
</header> </header>
); );
} }
_onChange = evt => {
this.setState({ labelInput: evt.target.value });
};
_onAdd = () => {
console.log(this.state.labelInput);
this.setState({ labelInput: '' });
};
} }

23
step1-07/README.md Normal file
View File

@@ -0,0 +1,23 @@
already done
Types in header
TodoApp methods
filteredTodos in List
demo
Add Types to TodoApp
change 'filter' value
Types in List
pass complete to List - show types, change complete to boolean/, filter
add complete, pass to item (prop drilling)
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
exercise
Add types to footer
Add onClick to button
Add types to header
Add setFilter to filter buttons
add 'addTodo' to onAdd function

View File

@@ -2,10 +2,11 @@ import React from 'react';
import { TodoFooter } from './components/TodoFooter'; import { TodoFooter } from './components/TodoFooter';
import { TodoHeader } from './components/TodoHeader'; import { TodoHeader } from './components/TodoHeader';
import { TodoList } from './components/TodoList'; import { TodoList } from './components/TodoList';
import { Todos, FilterTypes } from './TodoApp.types';
let index = 0; let index = 0;
export class TodoApp extends React.Component<any, any> { export class TodoApp extends React.Component<any, { todos: Todos; filter: FilterTypes }> {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
@@ -25,6 +26,8 @@ export class TodoApp extends React.Component<any, any> {
); );
} }
// business logic
private _addTodo = label => { private _addTodo = label => {
const { todos } = this.state; const { todos } = this.state;
const id = index++; const id = index++;
@@ -34,15 +37,6 @@ export class TodoApp extends React.Component<any, any> {
}); });
}; };
private _remove = id => {
const newTodos = { ...this.state.todos };
delete newTodos[id];
this.setState({
todos: newTodos
});
};
private _complete = id => { private _complete = id => {
const newTodos = { ...this.state.todos }; const newTodos = { ...this.state.todos };
newTodos[id].completed = !newTodos[id].completed; newTodos[id].completed = !newTodos[id].completed;
@@ -52,15 +46,6 @@ export class TodoApp extends React.Component<any, any> {
}); });
}; };
private _edit = (id, label) => {
const newTodos = { ...this.state.todos };
newTodos[id] = { ...newTodos[id], label };
this.setState({
todos: newTodos
});
};
private _clear = () => { private _clear = () => {
const { todos } = this.state; const { todos } = this.state;
const newTodos = {}; const newTodos = {};

View File

@@ -11,7 +11,7 @@ const nonWebpackedEntries = [];
function* getEntryPoint(step) { function* getEntryPoint(step) {
if (step.includes('step') || step.includes('playground')) { if (step.includes('step') || step.includes('playground')) {
for (let prefix of ['', 'demo/', 'exercise/']) { for (let prefix of ['', 'demo/', 'exercise/', 'final/']) {
for (let suffix of ['.js', '.jsx', '.ts', '.tsx']) { for (let suffix of ['.js', '.jsx', '.ts', '.tsx']) {
const entryRequest = `./${step}/${prefix}src/index${suffix}`; const entryRequest = `./${step}/${prefix}src/index${suffix}`;
if (fs.existsSync(entryRequest)) { if (fs.existsSync(entryRequest)) {