From 88cb5ddff3567696138e2ec1d43420757d26177b Mon Sep 17 00:00:00 2001 From: Micah Godbolt Date: Thu, 21 Feb 2019 21:49:50 -0800 Subject: [PATCH 1/2] set up demo, exercise, final folders --- step1-05/final/src/{App.tsx => TodoApp.tsx} | 0 step1-05/final/src/index.tsx | 8 +-- step1-06/README.md | 23 ++++--- step1-06/demo/index.html | 9 +++ step1-06/demo/src/TodoApp.tsx | 16 +++++ step1-06/demo/src/components/TodoFooter.tsx | 11 +++ step1-06/demo/src/components/TodoHeader.tsx | 29 ++++++++ step1-06/demo/src/components/TodoList.tsx | 20 ++++++ step1-06/demo/src/components/TodoListItem.tsx | 13 ++++ step1-06/{ => demo}/src/index.tsx | 0 step1-06/{ => demo}/src/style.css | 0 step1-06/exercise/index.html | 9 +++ step1-06/{ => exercise}/src/TodoApp.tsx | 0 .../exercise/src/components/TodoFooter.tsx | 11 +++ .../exercise/src/components/TodoHeader.tsx | 30 ++++++++ .../src/components/TodoList.tsx | 0 .../exercise/src/components/TodoListItem.tsx | 13 ++++ {step1-07 => step1-06/exercise}/src/index.tsx | 0 {step1-07 => step1-06/exercise}/src/style.css | 0 step1-06/final/index.html | 9 +++ step1-06/final/src/TodoApp.tsx | 41 +++++++++++ .../{ => final}/src/components/TodoFooter.tsx | 0 .../{ => final}/src/components/TodoHeader.tsx | 0 step1-06/final/src/components/TodoList.tsx | 19 +++++ .../src/components/TodoListItem.tsx | 0 step1-06/final/src/index.tsx | 4 ++ step1-06/final/src/style.css | 49 +++++++++++++ step1-06/index.html | 18 +++-- step1-07/README.md | 32 +++++++-- step1-07/demo/index.html | 7 ++ step1-07/demo/src/TodoApp.tsx | 69 +++++++++++++++++++ step1-07/{ => demo}/src/TodoApp.types.ts | 0 step1-07/demo/src/components/TodoFooter.tsx | 14 ++++ step1-07/demo/src/components/TodoHeader.tsx | 31 +++++++++ step1-07/demo/src/components/TodoList.tsx | 21 ++++++ step1-07/demo/src/components/TodoListItem.tsx | 16 +++++ step1-07/demo/src/index.tsx | 4 ++ step1-07/demo/src/style.css | 49 +++++++++++++ step1-07/exercise/index.html | 9 +++ step1-07/{ => exercise}/src/TodoApp.tsx | 0 step1-07/exercise/src/TodoApp.types.ts | 10 +++ .../exercise/src/components/TodoFooter.tsx | 14 ++++ .../exercise/src/components/TodoHeader.tsx | 31 +++++++++ .../src/components/TodoList.tsx | 0 .../src/components/TodoListItem.tsx | 0 step1-07/exercise/src/index.tsx | 4 ++ step1-07/exercise/src/style.css | 49 +++++++++++++ step1-07/final/index.html | 9 +++ step1-07/final/src/TodoApp.tsx | 69 +++++++++++++++++++ step1-07/final/src/TodoApp.types.ts | 10 +++ .../{ => final}/src/components/TodoFooter.tsx | 0 .../{ => final}/src/components/TodoHeader.tsx | 0 step1-07/final/src/components/TodoList.tsx | 27 ++++++++ .../final/src/components/TodoListItem.tsx | 21 ++++++ step1-07/final/src/index.tsx | 4 ++ step1-07/final/src/style.css | 49 +++++++++++++ step1-07/index.html | 18 +++-- 57 files changed, 869 insertions(+), 30 deletions(-) rename step1-05/final/src/{App.tsx => TodoApp.tsx} (100%) create mode 100644 step1-06/demo/index.html create mode 100644 step1-06/demo/src/TodoApp.tsx create mode 100644 step1-06/demo/src/components/TodoFooter.tsx create mode 100644 step1-06/demo/src/components/TodoHeader.tsx create mode 100644 step1-06/demo/src/components/TodoList.tsx create mode 100644 step1-06/demo/src/components/TodoListItem.tsx rename step1-06/{ => demo}/src/index.tsx (100%) rename step1-06/{ => demo}/src/style.css (100%) create mode 100644 step1-06/exercise/index.html rename step1-06/{ => exercise}/src/TodoApp.tsx (100%) create mode 100644 step1-06/exercise/src/components/TodoFooter.tsx create mode 100644 step1-06/exercise/src/components/TodoHeader.tsx rename step1-06/{ => exercise}/src/components/TodoList.tsx (100%) create mode 100644 step1-06/exercise/src/components/TodoListItem.tsx rename {step1-07 => step1-06/exercise}/src/index.tsx (100%) rename {step1-07 => step1-06/exercise}/src/style.css (100%) create mode 100644 step1-06/final/index.html create mode 100644 step1-06/final/src/TodoApp.tsx rename step1-06/{ => final}/src/components/TodoFooter.tsx (100%) rename step1-06/{ => final}/src/components/TodoHeader.tsx (100%) create mode 100644 step1-06/final/src/components/TodoList.tsx rename step1-06/{ => final}/src/components/TodoListItem.tsx (100%) create mode 100644 step1-06/final/src/index.tsx create mode 100644 step1-06/final/src/style.css create mode 100644 step1-07/demo/index.html create mode 100644 step1-07/demo/src/TodoApp.tsx rename step1-07/{ => demo}/src/TodoApp.types.ts (100%) create mode 100644 step1-07/demo/src/components/TodoFooter.tsx create mode 100644 step1-07/demo/src/components/TodoHeader.tsx create mode 100644 step1-07/demo/src/components/TodoList.tsx create mode 100644 step1-07/demo/src/components/TodoListItem.tsx create mode 100644 step1-07/demo/src/index.tsx create mode 100644 step1-07/demo/src/style.css create mode 100644 step1-07/exercise/index.html rename step1-07/{ => exercise}/src/TodoApp.tsx (100%) create mode 100644 step1-07/exercise/src/TodoApp.types.ts create mode 100644 step1-07/exercise/src/components/TodoFooter.tsx create mode 100644 step1-07/exercise/src/components/TodoHeader.tsx rename step1-07/{ => exercise}/src/components/TodoList.tsx (100%) rename step1-07/{ => exercise}/src/components/TodoListItem.tsx (100%) create mode 100644 step1-07/exercise/src/index.tsx create mode 100644 step1-07/exercise/src/style.css create mode 100644 step1-07/final/index.html create mode 100644 step1-07/final/src/TodoApp.tsx create mode 100644 step1-07/final/src/TodoApp.types.ts rename step1-07/{ => final}/src/components/TodoFooter.tsx (100%) rename step1-07/{ => final}/src/components/TodoHeader.tsx (100%) create mode 100644 step1-07/final/src/components/TodoList.tsx create mode 100644 step1-07/final/src/components/TodoListItem.tsx create mode 100644 step1-07/final/src/index.tsx create mode 100644 step1-07/final/src/style.css diff --git a/step1-05/final/src/App.tsx b/step1-05/final/src/TodoApp.tsx similarity index 100% rename from step1-05/final/src/App.tsx rename to step1-05/final/src/TodoApp.tsx diff --git a/step1-05/final/src/index.tsx b/step1-05/final/src/index.tsx index 3289ec8..ccf63e2 100644 --- a/step1-05/final/src/index.tsx +++ b/step1-05/final/src/index.tsx @@ -1,4 +1,4 @@ -import React from "react"; -import ReactDOM from "react-dom"; -import { TodoApp } from "./App"; -ReactDOM.render(, document.getElementById("app")); +import React from 'react'; +import ReactDOM from 'react-dom'; +import { TodoApp } from './TodoApp'; +ReactDOM.render(, document.getElementById('app')); diff --git a/step1-06/README.md b/step1-06/README.md index 696dc0c..8825198 100644 --- a/step1-06/README.md +++ b/step1-06/README.md @@ -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 diff --git a/step1-06/demo/index.html b/step1-06/demo/index.html new file mode 100644 index 0000000..de2c99d --- /dev/null +++ b/step1-06/demo/index.html @@ -0,0 +1,9 @@ + + + + +
+ + + + diff --git a/step1-06/demo/src/TodoApp.tsx b/step1-06/demo/src/TodoApp.tsx new file mode 100644 index 0000000..0f6e89a --- /dev/null +++ b/step1-06/demo/src/TodoApp.tsx @@ -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 ( +
+ + + +
+ ); + } +} diff --git a/step1-06/demo/src/components/TodoFooter.tsx b/step1-06/demo/src/components/TodoFooter.tsx new file mode 100644 index 0000000..c936963 --- /dev/null +++ b/step1-06/demo/src/components/TodoFooter.tsx @@ -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 ( +
+ 4 items left + +
+ ); +}; diff --git a/step1-06/demo/src/components/TodoHeader.tsx b/step1-06/demo/src/components/TodoHeader.tsx new file mode 100644 index 0000000..b5622ea --- /dev/null +++ b/step1-06/demo/src/components/TodoHeader.tsx @@ -0,0 +1,29 @@ +import React from 'react'; + +export class TodoHeader extends React.Component { + constructor(props) { + super(props); + this.state = { labelInput: '' }; + } + + render() { + return ( +
+

todos

+
+ + +
+ +
+ ); + } + + _onChange = evt => { + this.setState({ labelInput: evt.target.value }); + }; +} diff --git a/step1-06/demo/src/components/TodoList.tsx b/step1-06/demo/src/components/TodoList.tsx new file mode 100644 index 0000000..29ca769 --- /dev/null +++ b/step1-06/demo/src/components/TodoList.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { TodoListItem } from './TodoListItem'; + +export class TodoList extends React.Component { + 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 ( +
    + + + + +
+ ); + } +} diff --git a/step1-06/demo/src/components/TodoListItem.tsx b/step1-06/demo/src/components/TodoListItem.tsx new file mode 100644 index 0000000..1bff0f7 --- /dev/null +++ b/step1-06/demo/src/components/TodoListItem.tsx @@ -0,0 +1,13 @@ +import React from "react"; + +export class TodoListItem extends React.Component { + render() { + return ( +
  • + +
  • + ); + } +} diff --git a/step1-06/src/index.tsx b/step1-06/demo/src/index.tsx similarity index 100% rename from step1-06/src/index.tsx rename to step1-06/demo/src/index.tsx diff --git a/step1-06/src/style.css b/step1-06/demo/src/style.css similarity index 100% rename from step1-06/src/style.css rename to step1-06/demo/src/style.css diff --git a/step1-06/exercise/index.html b/step1-06/exercise/index.html new file mode 100644 index 0000000..de2c99d --- /dev/null +++ b/step1-06/exercise/index.html @@ -0,0 +1,9 @@ + + + + +
    + + + + diff --git a/step1-06/src/TodoApp.tsx b/step1-06/exercise/src/TodoApp.tsx similarity index 100% rename from step1-06/src/TodoApp.tsx rename to step1-06/exercise/src/TodoApp.tsx diff --git a/step1-06/exercise/src/components/TodoFooter.tsx b/step1-06/exercise/src/components/TodoFooter.tsx new file mode 100644 index 0000000..c936963 --- /dev/null +++ b/step1-06/exercise/src/components/TodoFooter.tsx @@ -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 ( +
    + 4 items left + +
    + ); +}; diff --git a/step1-06/exercise/src/components/TodoHeader.tsx b/step1-06/exercise/src/components/TodoHeader.tsx new file mode 100644 index 0000000..408a91c --- /dev/null +++ b/step1-06/exercise/src/components/TodoHeader.tsx @@ -0,0 +1,30 @@ +import React from 'react'; + +export class TodoHeader extends React.Component { + constructor(props) { + super(props); + this.state = { labelInput: '' }; + } + + render() { + const { filter } = this.props; + + return ( +
    +

    todos

    +
    + + +
    + +
    + ); + } + _onChange = evt => { + this.setState({ labelInput: evt.target.value }); + }; +} diff --git a/step1-06/src/components/TodoList.tsx b/step1-06/exercise/src/components/TodoList.tsx similarity index 100% rename from step1-06/src/components/TodoList.tsx rename to step1-06/exercise/src/components/TodoList.tsx diff --git a/step1-06/exercise/src/components/TodoListItem.tsx b/step1-06/exercise/src/components/TodoListItem.tsx new file mode 100644 index 0000000..6bdcb59 --- /dev/null +++ b/step1-06/exercise/src/components/TodoListItem.tsx @@ -0,0 +1,13 @@ +import React from 'react'; + +export class TodoListItem extends React.Component { + render() { + return ( +
  • + +
  • + ); + } +} diff --git a/step1-07/src/index.tsx b/step1-06/exercise/src/index.tsx similarity index 100% rename from step1-07/src/index.tsx rename to step1-06/exercise/src/index.tsx diff --git a/step1-07/src/style.css b/step1-06/exercise/src/style.css similarity index 100% rename from step1-07/src/style.css rename to step1-06/exercise/src/style.css diff --git a/step1-06/final/index.html b/step1-06/final/index.html new file mode 100644 index 0000000..de2c99d --- /dev/null +++ b/step1-06/final/index.html @@ -0,0 +1,9 @@ + + + + +
    + + + + diff --git a/step1-06/final/src/TodoApp.tsx b/step1-06/final/src/TodoApp.tsx new file mode 100644 index 0000000..b0dbfba --- /dev/null +++ b/step1-06/final/src/TodoApp.tsx @@ -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 { + 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 ( +
    + + + +
    + ); + } +} diff --git a/step1-06/src/components/TodoFooter.tsx b/step1-06/final/src/components/TodoFooter.tsx similarity index 100% rename from step1-06/src/components/TodoFooter.tsx rename to step1-06/final/src/components/TodoFooter.tsx diff --git a/step1-06/src/components/TodoHeader.tsx b/step1-06/final/src/components/TodoHeader.tsx similarity index 100% rename from step1-06/src/components/TodoHeader.tsx rename to step1-06/final/src/components/TodoHeader.tsx diff --git a/step1-06/final/src/components/TodoList.tsx b/step1-06/final/src/components/TodoList.tsx new file mode 100644 index 0000000..a92faa0 --- /dev/null +++ b/step1-06/final/src/components/TodoList.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { TodoListItem } from './TodoListItem'; + +export class TodoList extends React.Component { + 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 ( +
      + {filteredTodos.map(id => ( + + ))} +
    + ); + } +} diff --git a/step1-06/src/components/TodoListItem.tsx b/step1-06/final/src/components/TodoListItem.tsx similarity index 100% rename from step1-06/src/components/TodoListItem.tsx rename to step1-06/final/src/components/TodoListItem.tsx diff --git a/step1-06/final/src/index.tsx b/step1-06/final/src/index.tsx new file mode 100644 index 0000000..ccf63e2 --- /dev/null +++ b/step1-06/final/src/index.tsx @@ -0,0 +1,4 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { TodoApp } from './TodoApp'; +ReactDOM.render(, document.getElementById('app')); diff --git a/step1-06/final/src/style.css b/step1-06/final/src/style.css new file mode 100644 index 0000000..4163a3a --- /dev/null +++ b/step1-06/final/src/style.css @@ -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; +} diff --git a/step1-06/index.html b/step1-06/index.html index de2c99d..dadfb94 100644 --- a/step1-06/index.html +++ b/step1-06/index.html @@ -1,9 +1,15 @@ - - - -
    + + + + + + +
    + +
    - - diff --git a/step1-07/README.md b/step1-07/README.md index 6b9c40d..75c4945 100644 --- a/step1-07/README.md +++ b/step1-07/README.md @@ -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 diff --git a/step1-07/demo/index.html b/step1-07/demo/index.html new file mode 100644 index 0000000..c8c2823 --- /dev/null +++ b/step1-07/demo/index.html @@ -0,0 +1,7 @@ + + + + +
    + + diff --git a/step1-07/demo/src/TodoApp.tsx b/step1-07/demo/src/TodoApp.tsx new file mode 100644 index 0000000..759b8eb --- /dev/null +++ b/step1-07/demo/src/TodoApp.tsx @@ -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 { + constructor(props) { + super(props); + this.state = { + todos: {}, + filter: 'all' + }; + } + + render() { + const { filter, todos } = this.state; + return ( +
    + + + +
    + ); + } + + // 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 + }); + }; +} diff --git a/step1-07/src/TodoApp.types.ts b/step1-07/demo/src/TodoApp.types.ts similarity index 100% rename from step1-07/src/TodoApp.types.ts rename to step1-07/demo/src/TodoApp.types.ts diff --git a/step1-07/demo/src/components/TodoFooter.tsx b/step1-07/demo/src/components/TodoFooter.tsx new file mode 100644 index 0000000..0d86f55 --- /dev/null +++ b/step1-07/demo/src/components/TodoFooter.tsx @@ -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 ( +
    + + {itemCount} item{itemCount > 1 ? 's' : ''} left + + +
    + ); +}; diff --git a/step1-07/demo/src/components/TodoHeader.tsx b/step1-07/demo/src/components/TodoHeader.tsx new file mode 100644 index 0000000..7db8f6e --- /dev/null +++ b/step1-07/demo/src/components/TodoHeader.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { FilterTypes } from '../TodoApp.types'; + +export class TodoHeader extends React.Component { + constructor(props) { + super(props); + this.state = { labelInput: '' }; + } + + render() { + const { filter } = this.props; + return ( +
    +

    todos

    +
    + + +
    + +
    + ); + } + + _onChange = evt => { + this.setState({ labelInput: evt.target.value }); + }; +} diff --git a/step1-07/demo/src/components/TodoList.tsx b/step1-07/demo/src/components/TodoList.tsx new file mode 100644 index 0000000..a281227 --- /dev/null +++ b/step1-07/demo/src/components/TodoList.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { TodoListItem } from './TodoListItem'; +import { FilterTypes, Todos } from '../TodoApp.types'; + +export class TodoList extends React.Component { + 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 ( +
      + {filteredTodos.map(id => ( + + ))} +
    + ); + } +} diff --git a/step1-07/demo/src/components/TodoListItem.tsx b/step1-07/demo/src/components/TodoListItem.tsx new file mode 100644 index 0000000..b4b49b6 --- /dev/null +++ b/step1-07/demo/src/components/TodoListItem.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { TodoItem } from '../TodoApp.types'; + +export class TodoListItem extends React.Component { + render() { + const { label, completed } = this.props; + + return ( +
  • + +
  • + ); + } +} diff --git a/step1-07/demo/src/index.tsx b/step1-07/demo/src/index.tsx new file mode 100644 index 0000000..ccf63e2 --- /dev/null +++ b/step1-07/demo/src/index.tsx @@ -0,0 +1,4 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { TodoApp } from './TodoApp'; +ReactDOM.render(, document.getElementById('app')); diff --git a/step1-07/demo/src/style.css b/step1-07/demo/src/style.css new file mode 100644 index 0000000..4163a3a --- /dev/null +++ b/step1-07/demo/src/style.css @@ -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; +} diff --git a/step1-07/exercise/index.html b/step1-07/exercise/index.html new file mode 100644 index 0000000..de2c99d --- /dev/null +++ b/step1-07/exercise/index.html @@ -0,0 +1,9 @@ + + + + +
    + + + + diff --git a/step1-07/src/TodoApp.tsx b/step1-07/exercise/src/TodoApp.tsx similarity index 100% rename from step1-07/src/TodoApp.tsx rename to step1-07/exercise/src/TodoApp.tsx diff --git a/step1-07/exercise/src/TodoApp.types.ts b/step1-07/exercise/src/TodoApp.types.ts new file mode 100644 index 0000000..eb5437e --- /dev/null +++ b/step1-07/exercise/src/TodoApp.types.ts @@ -0,0 +1,10 @@ +export type FilterTypes = 'all' | 'active' | 'completed'; + +export interface TodoItem { + label: string; + completed: boolean; +} + +export interface Todos { + [id: string]: TodoItem; +} diff --git a/step1-07/exercise/src/components/TodoFooter.tsx b/step1-07/exercise/src/components/TodoFooter.tsx new file mode 100644 index 0000000..fdda04a --- /dev/null +++ b/step1-07/exercise/src/components/TodoFooter.tsx @@ -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 ( +
    + + {itemCount} item{itemCount > 1 ? 's' : ''} left + + +
    + ); +}; diff --git a/step1-07/exercise/src/components/TodoHeader.tsx b/step1-07/exercise/src/components/TodoHeader.tsx new file mode 100644 index 0000000..7db8f6e --- /dev/null +++ b/step1-07/exercise/src/components/TodoHeader.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { FilterTypes } from '../TodoApp.types'; + +export class TodoHeader extends React.Component { + constructor(props) { + super(props); + this.state = { labelInput: '' }; + } + + render() { + const { filter } = this.props; + return ( +
    +

    todos

    +
    + + +
    + +
    + ); + } + + _onChange = evt => { + this.setState({ labelInput: evt.target.value }); + }; +} diff --git a/step1-07/src/components/TodoList.tsx b/step1-07/exercise/src/components/TodoList.tsx similarity index 100% rename from step1-07/src/components/TodoList.tsx rename to step1-07/exercise/src/components/TodoList.tsx diff --git a/step1-07/src/components/TodoListItem.tsx b/step1-07/exercise/src/components/TodoListItem.tsx similarity index 100% rename from step1-07/src/components/TodoListItem.tsx rename to step1-07/exercise/src/components/TodoListItem.tsx diff --git a/step1-07/exercise/src/index.tsx b/step1-07/exercise/src/index.tsx new file mode 100644 index 0000000..ccf63e2 --- /dev/null +++ b/step1-07/exercise/src/index.tsx @@ -0,0 +1,4 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { TodoApp } from './TodoApp'; +ReactDOM.render(, document.getElementById('app')); diff --git a/step1-07/exercise/src/style.css b/step1-07/exercise/src/style.css new file mode 100644 index 0000000..4163a3a --- /dev/null +++ b/step1-07/exercise/src/style.css @@ -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; +} diff --git a/step1-07/final/index.html b/step1-07/final/index.html new file mode 100644 index 0000000..de2c99d --- /dev/null +++ b/step1-07/final/index.html @@ -0,0 +1,9 @@ + + + + +
    + + + + diff --git a/step1-07/final/src/TodoApp.tsx b/step1-07/final/src/TodoApp.tsx new file mode 100644 index 0000000..b24da27 --- /dev/null +++ b/step1-07/final/src/TodoApp.tsx @@ -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 { + constructor(props) { + super(props); + this.state = { + todos: {}, + filter: 'all' + }; + } + + render() { + const { filter, todos } = this.state; + return ( +
    + + + +
    + ); + } + + // 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 + }); + }; +} diff --git a/step1-07/final/src/TodoApp.types.ts b/step1-07/final/src/TodoApp.types.ts new file mode 100644 index 0000000..eb5437e --- /dev/null +++ b/step1-07/final/src/TodoApp.types.ts @@ -0,0 +1,10 @@ +export type FilterTypes = 'all' | 'active' | 'completed'; + +export interface TodoItem { + label: string; + completed: boolean; +} + +export interface Todos { + [id: string]: TodoItem; +} diff --git a/step1-07/src/components/TodoFooter.tsx b/step1-07/final/src/components/TodoFooter.tsx similarity index 100% rename from step1-07/src/components/TodoFooter.tsx rename to step1-07/final/src/components/TodoFooter.tsx diff --git a/step1-07/src/components/TodoHeader.tsx b/step1-07/final/src/components/TodoHeader.tsx similarity index 100% rename from step1-07/src/components/TodoHeader.tsx rename to step1-07/final/src/components/TodoHeader.tsx diff --git a/step1-07/final/src/components/TodoList.tsx b/step1-07/final/src/components/TodoList.tsx new file mode 100644 index 0000000..e6419e9 --- /dev/null +++ b/step1-07/final/src/components/TodoList.tsx @@ -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 { + 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 ( +
      + {filteredTodos.map(id => ( + + ))} +
    + ); + } +} diff --git a/step1-07/final/src/components/TodoListItem.tsx b/step1-07/final/src/components/TodoListItem.tsx new file mode 100644 index 0000000..3f359ce --- /dev/null +++ b/step1-07/final/src/components/TodoListItem.tsx @@ -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 { + render() { + const { label, completed, complete, id } = this.props; + + return ( +
  • + +
  • + ); + } +} diff --git a/step1-07/final/src/index.tsx b/step1-07/final/src/index.tsx new file mode 100644 index 0000000..ccf63e2 --- /dev/null +++ b/step1-07/final/src/index.tsx @@ -0,0 +1,4 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { TodoApp } from './TodoApp'; +ReactDOM.render(, document.getElementById('app')); diff --git a/step1-07/final/src/style.css b/step1-07/final/src/style.css new file mode 100644 index 0000000..4163a3a --- /dev/null +++ b/step1-07/final/src/style.css @@ -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; +} diff --git a/step1-07/index.html b/step1-07/index.html index de2c99d..dadfb94 100644 --- a/step1-07/index.html +++ b/step1-07/index.html @@ -1,9 +1,15 @@ - - - -
    + + + + + + +
    + +
    - - From 4f7b9e4747c7a24e178d1d2cf1ea4e53a8c49694 Mon Sep 17 00:00:00 2001 From: Micah Godbolt Date: Fri, 22 Feb 2019 12:21:40 -0800 Subject: [PATCH 2/2] js updates --- docs/step1-02/index.html | 2 +- docs/step1-02/style.css | 4 +- docs/step1-03/index.html | 2 +- docs/step1-03/style.css | 6 +- docs/step1-05/src/components/TodoHeader.tsx | 2 +- docs/step1-05/src/style.css | 6 +- docs/step1-06/src/components/TodoHeader.tsx | 6 +- docs/step1-06/src/style.css | 6 +- docs/step1-07/src/components/TodoHeader.tsx | 6 +- docs/step1-07/src/style.css | 6 +- step1-02/README.md | 94 +++++++++++++++++-- step1-02/demo/index.html | 1 - step1-02/demo/style.css | 4 + step1-02/exercise/index.html | 9 +- step1-02/exercise/style.css | 2 +- step1-02/final/index.html | 2 +- step1-02/final/style.css | 2 +- step1-03/README.md | 26 +++-- step1-03/demo/index.html | 16 ++-- step1-03/demo/style.css | 2 +- step1-03/exercise/index.html | 16 ++-- step1-03/exercise/style.css | 2 +- step1-03/final/index.html | 16 ++-- step1-03/final/style.css | 2 +- step1-04/README.md | 2 +- step1-04/demo/index.html | 6 -- step1-04/demo/src/App.tsx | 14 --- step1-04/demo/src/components/Counter.tsx | 24 +---- step1-04/demo/src/index.tsx | 4 - step1-05/demo/src/style.css | 2 +- .../exercise/src/components/TodoHeader.tsx | 2 +- step1-05/exercise/src/style.css | 2 +- step1-05/final/src/components/TodoHeader.tsx | 2 +- step1-05/final/src/style.css | 2 +- step1-06/demo/src/components/TodoHeader.tsx | 2 +- step1-06/demo/src/style.css | 2 +- .../exercise/src/components/TodoHeader.tsx | 6 +- step1-06/exercise/src/style.css | 2 +- step1-06/final/src/components/TodoHeader.tsx | 6 +- step1-06/final/src/style.css | 2 +- step1-07/demo/src/components/TodoHeader.tsx | 6 +- step1-07/demo/src/style.css | 2 +- .../exercise/src/components/TodoHeader.tsx | 6 +- step1-07/exercise/src/style.css | 2 +- step1-07/final/src/components/TodoHeader.tsx | 6 +- step1-07/final/src/style.css | 2 +- 46 files changed, 200 insertions(+), 144 deletions(-) diff --git a/docs/step1-02/index.html b/docs/step1-02/index.html index 7c9d40d..a48e0f8 100644 --- a/docs/step1-02/index.html +++ b/docs/step1-02/index.html @@ -5,7 +5,7 @@

    todos

    - +
    diff --git a/docs/step1-02/style.css b/docs/step1-02/style.css index 15642d5..6274d33 100644 --- a/docs/step1-02/style.css +++ b/docs/step1-02/style.css @@ -1,5 +1,5 @@ body { - font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; width: 400px; margin: 20px auto; } @@ -28,7 +28,7 @@ h1 { background: transparent; border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } diff --git a/docs/step1-03/index.html b/docs/step1-03/index.html index c9278ac..bffbf7f 100644 --- a/docs/step1-03/index.html +++ b/docs/step1-03/index.html @@ -8,7 +8,7 @@ Add
    - +
    diff --git a/docs/step1-03/style.css b/docs/step1-03/style.css index c897b4c..347bb57 100644 --- a/docs/step1-03/style.css +++ b/docs/step1-03/style.css @@ -1,5 +1,5 @@ body { - font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; width: 400px; margin: 20px auto; } @@ -28,7 +28,7 @@ h1 { background: transparent; border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } @@ -47,4 +47,4 @@ footer span { .hidden { display: none; -} \ No newline at end of file +} diff --git a/docs/step1-05/src/components/TodoHeader.tsx b/docs/step1-05/src/components/TodoHeader.tsx index aa1ec8b..b6a566b 100644 --- a/docs/step1-05/src/components/TodoHeader.tsx +++ b/docs/step1-05/src/components/TodoHeader.tsx @@ -8,7 +8,7 @@ export class TodoHeader extends React.Component {
    - +
    diff --git a/docs/step1-05/src/style.css b/docs/step1-05/src/style.css index c897b4c..347bb57 100644 --- a/docs/step1-05/src/style.css +++ b/docs/step1-05/src/style.css @@ -1,5 +1,5 @@ body { - font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; width: 400px; margin: 20px auto; } @@ -28,7 +28,7 @@ h1 { background: transparent; border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } @@ -47,4 +47,4 @@ footer span { .hidden { display: none; -} \ No newline at end of file +} diff --git a/docs/step1-06/src/components/TodoHeader.tsx b/docs/step1-06/src/components/TodoHeader.tsx index c26e54b..c35fa7a 100644 --- a/docs/step1-06/src/components/TodoHeader.tsx +++ b/docs/step1-06/src/components/TodoHeader.tsx @@ -9,9 +9,9 @@ export class TodoHeader extends React.Component {
    - - - + + +
    ); diff --git a/docs/step1-06/src/style.css b/docs/step1-06/src/style.css index c897b4c..347bb57 100644 --- a/docs/step1-06/src/style.css +++ b/docs/step1-06/src/style.css @@ -1,5 +1,5 @@ body { - font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; width: 400px; margin: 20px auto; } @@ -28,7 +28,7 @@ h1 { background: transparent; border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } @@ -47,4 +47,4 @@ footer span { .hidden { display: none; -} \ No newline at end of file +} diff --git a/docs/step1-07/src/components/TodoHeader.tsx b/docs/step1-07/src/components/TodoHeader.tsx index 99bda01..1c8cb08 100644 --- a/docs/step1-07/src/components/TodoHeader.tsx +++ b/docs/step1-07/src/components/TodoHeader.tsx @@ -23,13 +23,13 @@ export class TodoHeader extends React.Component { Add
    - - -
    diff --git a/docs/step1-07/src/style.css b/docs/step1-07/src/style.css index c897b4c..347bb57 100644 --- a/docs/step1-07/src/style.css +++ b/docs/step1-07/src/style.css @@ -1,5 +1,5 @@ body { - font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; width: 400px; margin: 20px auto; } @@ -28,7 +28,7 @@ h1 { background: transparent; border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } @@ -47,4 +47,4 @@ footer span { .hidden { display: none; -} \ No newline at end of file +} diff --git a/step1-02/README.md b/step1-02/README.md index 151ab5a..2b29ba0 100644 --- a/step1-02/README.md +++ b/step1-02/README.md @@ -1,13 +1,95 @@ ## HTML and CSS +Every website, application, form or component starts with markup. The HTML will change over time as you develop, but a first pass helps you understand the UI you are trying to build. + ## Demo -Write html tag down to ul > li, footer -add CSS link -Add active styles, describe specificity +In this exercise we will scaffold out some HTML for out Todo app, and add some basic styling to it. + +### Page scaffold + +```html + + + + + +``` + +1. The DOCTYPE tells the browser that this file is written in modern HTML. +2. The HTML tag wraps the entire page, and is the page root. Nothing is placed outside of those tags. Attributes can be set on HTML +3. Head will contain all of the page's meta data, in this case a link to our css file +4. Body is where all of the visible content should be placed. + +### Content Sectioning + +As we saw in the previous demo, HTML elements can be used to describe different content sections of the applications. Let's add `header`, `main` and `footer`, as well as populate the header with an `h1`, addTodo div, and `nav` for our filters. + +```html + +
    +

    +
    + +
    +
    +
    + +``` + +> Note that a `form` element would have been more semantic than a `div`, but we aren't using this form to POST to a server, so for this example a div is easier to use. + +### Updating the header + +The header of our page is where most of the action is going to happen. First, lets give our page a title, adding 'TODO' to our `h1`. Then we can add an input and button to our `addTodo` div. + +```html + +``` + +#### Navigation + +The navigation for this application is quite simple. We want users to be able to switch between three filtered states. Since we need to track which state is currently selected, we'll add that as a class on the first item. + +```html + +``` + +### Adding styles + +Now that we've got the top of our application scaffolded, we can add some our styles in the head. + +```html + + + +``` + +### Updating styles + +It looks like the selected button isn't getting any special styles. Let's dig in and see why that is. + +Open up the browser inspector and target our 'all' button. You'll notice that the blue style is present on the list, but it is being overriden by the `border: none` above it. This is a situation where specificity is winning out over the cascade. + +> **Cascade** states that if two selectors are equal, the lowest one on the page wins + +> **Specificity** states that regardless of cascade, the selector with the highest specificity wins + +To fix this problem we need to either reduce the specificity of our button styles, or increase the specificity of the selected style. In this situation we will add `.filter` in front of the `.selected` selector, because the selected style only applies to the filter anyway. ## Exercise -Update list item to match (already styled) -duplicate 3 more times -Add and style footer content +1. Add an unordered list with class `todos` to the main section +2. Add 4 list items with class `todo` inside of that list with the following content + `` +3. Add a span and a button to your footer +4. Span content should be `4 items left` and button should say `Clear Completed` and have a class of `submit` +5. Go into the CSS file and add `display: flex` to the footer. Also add `flex-grow:1` to the span inside of the footer + +> Hint: Look back at the CSS demo to see the various ways you can use selectors to target existing HTML + +> There are many strategies for creating and organizing class names in a large application. This lesson is focused on using CSS selectors, not the optimized way to scale your CSS. diff --git a/step1-02/demo/index.html b/step1-02/demo/index.html index 0e76edd..e69de29 100644 --- a/step1-02/demo/index.html +++ b/step1-02/demo/index.html @@ -1 +0,0 @@ - diff --git a/step1-02/demo/style.css b/step1-02/demo/style.css index 4df1196..9ed149d 100644 --- a/step1-02/demo/style.css +++ b/step1-02/demo/style.css @@ -31,6 +31,10 @@ h1 { border: none; } +.selected { + border-bottom: 2px solid blue; +} + .todos { list-style: none; padding: 0; diff --git a/step1-02/exercise/index.html b/step1-02/exercise/index.html index 52cf71f..ee6a337 100644 --- a/step1-02/exercise/index.html +++ b/step1-02/exercise/index.html @@ -11,15 +11,12 @@
    -
    -
      -
    • Todo 1
    • -
    -
    +
    +
    diff --git a/step1-02/exercise/style.css b/step1-02/exercise/style.css index 986a4e1..b7b7c59 100644 --- a/step1-02/exercise/style.css +++ b/step1-02/exercise/style.css @@ -31,7 +31,7 @@ h1 { border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } diff --git a/step1-02/final/index.html b/step1-02/final/index.html index 0ea87e3..d382af1 100644 --- a/step1-02/final/index.html +++ b/step1-02/final/index.html @@ -11,7 +11,7 @@ diff --git a/step1-02/final/style.css b/step1-02/final/style.css index 4163a3a..12b482b 100644 --- a/step1-02/final/style.css +++ b/step1-02/final/style.css @@ -31,7 +31,7 @@ h1 { border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } diff --git a/step1-03/README.md b/step1-03/README.md index 3be1ffa..da92f8b 100644 --- a/step1-03/README.md +++ b/step1-03/README.md @@ -1,11 +1,25 @@ -Demo +## Javascript Demo -already done +Now that we a UI that looks like a todo app, we need to add functionality to make it **function** like a todo app. In this example we are going to use raw Javascript explicitly modify our application as we interact with it. This will be in stark contrast to the implicit approach we will take when we do this with React in the next exercise. -- addTodo -- filter -- filter() -- getTodoText +> Keep an eye on how often user actions directly modify the HTML on the page. You'll see this number drop to zero when we start using React. + +### Demo + +This demo starts off with a few elements already in place. Let's walk through what's already here. + +- **getTodoText()** - This is a quick helper function that returns the value inside of our textfield. Notice how some functions return values and how you can set that return to a variable. Other functions return nothing, but rather have side effects. +- **addTodo()** - This is the primary logic of our todo app. Here's how the lines break down. + 1. `todo` is set to equal the first todo item + 2. `newTodo` is a clone of todo. Passing true means it is a deep clone, so we get the todo's children as well. Cloning does not duplicate the DOM node. We'll need to insert it in step 4 + 3. We set the innerText of the `` to the value returned from getTodoText + > Note that if we left off the `()` we'd actully be assiging innerText to the 'function' instead of the function return + 4. Insert our new todo into the todo's parent (the `ul`), before our reference todo. [insertBefore](https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore) +- **filter()** - This function takes in a `filterName` string, and a `button` which is a reference to the clicked button. + 1. Remove any `selected` class names + 2. Add `selected` to the clicked button + 3. Get all of the todos with [querySelectAll](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll), and then loop through them. + 4. Set the `hidden` property of each todo based on the filter/state combination Walk through 'addTodo' attach addTodo to button diff --git a/step1-03/demo/index.html b/step1-03/demo/index.html index d03de04..3cd790b 100644 --- a/step1-03/demo/index.html +++ b/step1-03/demo/index.html @@ -8,10 +8,10 @@

    todos

    - +
    @@ -52,16 +52,16 @@ // updateRemaining(); } - function filter(scope, button) { - document.querySelector('.active').classList.remove('active'); - button.classList.add('active'); + function filter(filterName, button) { + document.querySelector('.selected').classList.remove('selected'); + button.classList.add('selected'); for (let todo of document.querySelectorAll('.todo')) { const checked = todo.querySelector('input').checked == true; - if (scope == 'all') { + if (filterName == 'all') { todo.hidden = false; - } else if (scope == 'active') { + } else if (filterName == 'active') { todo.hidden = checked; - } else if (scope == 'completed') { + } else if (filterName == 'completed') { todo.hidden = !checked; } } diff --git a/step1-03/demo/style.css b/step1-03/demo/style.css index 4163a3a..12b482b 100644 --- a/step1-03/demo/style.css +++ b/step1-03/demo/style.css @@ -31,7 +31,7 @@ h1 { border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } diff --git a/step1-03/exercise/index.html b/step1-03/exercise/index.html index 5894b7c..0c84bbe 100644 --- a/step1-03/exercise/index.html +++ b/step1-03/exercise/index.html @@ -8,10 +8,10 @@

    todos

    - +
    @@ -64,16 +64,16 @@ // clearCompleted - function filter(scope, button) { - document.querySelector('.active').classList.remove('active'); - button.classList.add('active'); + function filter(filterName, button) { + document.querySelector('.selected').classList.remove('selected'); + button.classList.add('selected'); for (let todo of document.querySelectorAll('.todo')) { const checked = todo.querySelector('input').checked == true; - if (scope == 'all') { + if (filterName == 'all') { todo.hidden = false; - } else if (scope == 'active') { + } else if (filterName == 'active') { todo.hidden = checked; - } else if (scope == 'completed') { + } else if (filterName == 'completed') { todo.hidden = !checked; } } diff --git a/step1-03/exercise/style.css b/step1-03/exercise/style.css index 4163a3a..12b482b 100644 --- a/step1-03/exercise/style.css +++ b/step1-03/exercise/style.css @@ -31,7 +31,7 @@ h1 { border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } diff --git a/step1-03/final/index.html b/step1-03/final/index.html index 9b5fcc3..4c5b24f 100644 --- a/step1-03/final/index.html +++ b/step1-03/final/index.html @@ -8,10 +8,10 @@

    todos

    - +
    @@ -72,16 +72,16 @@ updateRemaining(); } - function filter(scope, button) { - document.querySelector('.active').classList.remove('active'); - button.classList.add('active'); + function filter(filterName, button) { + document.querySelector('.selected').classList.remove('selected'); + button.classList.add('selected'); for (let todo of document.querySelectorAll('.todo')) { const checked = todo.querySelector('input').checked == true; - if (scope == 'all') { + if (filterName == 'all') { todo.hidden = false; - } else if (scope == 'active') { + } else if (filterName == 'active') { todo.hidden = checked; - } else if (scope == 'completed') { + } else if (filterName == 'completed') { todo.hidden = !checked; } } diff --git a/step1-03/final/style.css b/step1-03/final/style.css index 4163a3a..12b482b 100644 --- a/step1-03/final/style.css +++ b/step1-03/final/style.css @@ -31,7 +31,7 @@ h1 { border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } diff --git a/step1-04/README.md b/step1-04/README.md index 71bbf9f..64ab0ce 100644 --- a/step1-04/README.md +++ b/step1-04/README.md @@ -9,4 +9,4 @@ write index.html demo 'hello world' Write Counter Component with button -Demo Button, import into Component +Demo Button, import into Counter diff --git a/step1-04/demo/index.html b/step1-04/demo/index.html index 454cef5..e69de29 100644 --- a/step1-04/demo/index.html +++ b/step1-04/demo/index.html @@ -1,6 +0,0 @@ - - - -
    - - diff --git a/step1-04/demo/src/App.tsx b/step1-04/demo/src/App.tsx index f3dc2af..e69de29 100644 --- a/step1-04/demo/src/App.tsx +++ b/step1-04/demo/src/App.tsx @@ -1,14 +0,0 @@ -import React from 'react'; -import { Counter } from './components/Counter'; - -export class App extends React.Component { - render() { - return ( -
    -

    My App

    - - -
    - ); - } -} diff --git a/step1-04/demo/src/components/Counter.tsx b/step1-04/demo/src/components/Counter.tsx index dd8fa71..c92694a 100644 --- a/step1-04/demo/src/components/Counter.tsx +++ b/step1-04/demo/src/components/Counter.tsx @@ -1,27 +1,11 @@ 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 - }; - } +export class Counter extends React.Component { + render() { - const { counter } = this.state; - const { text } = this.props; + return ( -
    - {text}: {counter} - -
    + ); } } diff --git a/step1-04/demo/src/index.tsx b/step1-04/demo/src/index.tsx index 1d9694f..e69de29 100644 --- a/step1-04/demo/src/index.tsx +++ b/step1-04/demo/src/index.tsx @@ -1,4 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; -import { App } from "./App"; -ReactDOM.render(, document.getElementById("app")); diff --git a/step1-05/demo/src/style.css b/step1-05/demo/src/style.css index 4163a3a..12b482b 100644 --- a/step1-05/demo/src/style.css +++ b/step1-05/demo/src/style.css @@ -31,7 +31,7 @@ h1 { border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } diff --git a/step1-05/exercise/src/components/TodoHeader.tsx b/step1-05/exercise/src/components/TodoHeader.tsx index ba9b8b0..15758b7 100644 --- a/step1-05/exercise/src/components/TodoHeader.tsx +++ b/step1-05/exercise/src/components/TodoHeader.tsx @@ -10,7 +10,7 @@ export class TodoHeader extends React.Component { diff --git a/step1-05/exercise/src/style.css b/step1-05/exercise/src/style.css index 4163a3a..12b482b 100644 --- a/step1-05/exercise/src/style.css +++ b/step1-05/exercise/src/style.css @@ -31,7 +31,7 @@ h1 { border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } diff --git a/step1-05/final/src/components/TodoHeader.tsx b/step1-05/final/src/components/TodoHeader.tsx index ba9b8b0..15758b7 100644 --- a/step1-05/final/src/components/TodoHeader.tsx +++ b/step1-05/final/src/components/TodoHeader.tsx @@ -10,7 +10,7 @@ export class TodoHeader extends React.Component { diff --git a/step1-05/final/src/style.css b/step1-05/final/src/style.css index 4163a3a..12b482b 100644 --- a/step1-05/final/src/style.css +++ b/step1-05/final/src/style.css @@ -31,7 +31,7 @@ h1 { border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } diff --git a/step1-06/demo/src/components/TodoHeader.tsx b/step1-06/demo/src/components/TodoHeader.tsx index b5622ea..f310531 100644 --- a/step1-06/demo/src/components/TodoHeader.tsx +++ b/step1-06/demo/src/components/TodoHeader.tsx @@ -15,7 +15,7 @@ export class TodoHeader extends React.Component { diff --git a/step1-06/demo/src/style.css b/step1-06/demo/src/style.css index 4163a3a..12b482b 100644 --- a/step1-06/demo/src/style.css +++ b/step1-06/demo/src/style.css @@ -31,7 +31,7 @@ h1 { border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } diff --git a/step1-06/exercise/src/components/TodoHeader.tsx b/step1-06/exercise/src/components/TodoHeader.tsx index 408a91c..51830e9 100644 --- a/step1-06/exercise/src/components/TodoHeader.tsx +++ b/step1-06/exercise/src/components/TodoHeader.tsx @@ -17,9 +17,9 @@ export class TodoHeader extends React.Component {
    ); diff --git a/step1-06/exercise/src/style.css b/step1-06/exercise/src/style.css index 4163a3a..12b482b 100644 --- a/step1-06/exercise/src/style.css +++ b/step1-06/exercise/src/style.css @@ -31,7 +31,7 @@ h1 { border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } diff --git a/step1-06/final/src/components/TodoHeader.tsx b/step1-06/final/src/components/TodoHeader.tsx index b63967b..dcf8947 100644 --- a/step1-06/final/src/components/TodoHeader.tsx +++ b/step1-06/final/src/components/TodoHeader.tsx @@ -12,9 +12,9 @@ export class TodoHeader extends React.Component { ); diff --git a/step1-06/final/src/style.css b/step1-06/final/src/style.css index 4163a3a..12b482b 100644 --- a/step1-06/final/src/style.css +++ b/step1-06/final/src/style.css @@ -31,7 +31,7 @@ h1 { border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } diff --git a/step1-07/demo/src/components/TodoHeader.tsx b/step1-07/demo/src/components/TodoHeader.tsx index 7db8f6e..0608661 100644 --- a/step1-07/demo/src/components/TodoHeader.tsx +++ b/step1-07/demo/src/components/TodoHeader.tsx @@ -17,9 +17,9 @@ export class TodoHeader extends React.Component { ); diff --git a/step1-07/demo/src/style.css b/step1-07/demo/src/style.css index 4163a3a..12b482b 100644 --- a/step1-07/demo/src/style.css +++ b/step1-07/demo/src/style.css @@ -31,7 +31,7 @@ h1 { border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } diff --git a/step1-07/exercise/src/components/TodoHeader.tsx b/step1-07/exercise/src/components/TodoHeader.tsx index 7db8f6e..0608661 100644 --- a/step1-07/exercise/src/components/TodoHeader.tsx +++ b/step1-07/exercise/src/components/TodoHeader.tsx @@ -17,9 +17,9 @@ export class TodoHeader extends React.Component { ); diff --git a/step1-07/exercise/src/style.css b/step1-07/exercise/src/style.css index 4163a3a..12b482b 100644 --- a/step1-07/exercise/src/style.css +++ b/step1-07/exercise/src/style.css @@ -31,7 +31,7 @@ h1 { border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; } diff --git a/step1-07/final/src/components/TodoHeader.tsx b/step1-07/final/src/components/TodoHeader.tsx index 3d7b234..b71dd25 100644 --- a/step1-07/final/src/components/TodoHeader.tsx +++ b/step1-07/final/src/components/TodoHeader.tsx @@ -25,13 +25,13 @@ export class TodoHeader extends React.Component { diff --git a/step1-07/final/src/style.css b/step1-07/final/src/style.css index 4163a3a..12b482b 100644 --- a/step1-07/final/src/style.css +++ b/step1-07/final/src/style.css @@ -31,7 +31,7 @@ h1 { border: none; } -.filter .active { +.filter .selected { border-bottom: 2px solid blue; }