Break down Header and Footer into simpler components (#7)
This commit is contained in:
Родитель
03e473797d
Коммит
e4b93d2543
|
@ -1,8 +1,8 @@
|
|||
import * as React from 'react';
|
||||
|
||||
import Header from './Header';
|
||||
import Header from './header/Header';
|
||||
import Main from './Main';
|
||||
import Footer from './Footer';
|
||||
import Footer from './footer/Footer';
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import {observer} from 'mobx-react';
|
||||
import Store from '../store/store';
|
||||
import removeAllCompleted from '../actions/removeAllCompleted';
|
||||
import setFilter from '../actions/setFilter';
|
||||
import {FilterType} from '../store/schema';
|
||||
|
||||
@observer
|
||||
export default class Footer extends React.Component<any, any> {
|
||||
onClearCompleted = () => {
|
||||
removeAllCompleted();
|
||||
}
|
||||
|
||||
onSetFilter = (filter: FilterType) => {
|
||||
setFilter(filter);
|
||||
}
|
||||
|
||||
render() {
|
||||
let {itemsLeft, filter} = Store;
|
||||
|
||||
return (
|
||||
<footer className="footer">
|
||||
<span className="todo-count">{itemsLeft} Left</span>
|
||||
<ul className="filters">
|
||||
<li><a href="#" onClick={() => this.onSetFilter(FilterType.All)} className={filter == FilterType.All ? "selected" : ""}>All</a></li>
|
||||
<li><a href="#" onClick={() => this.onSetFilter(FilterType.Active)} className={filter == FilterType.Active ? "selected" : ""}>Active</a></li>
|
||||
<li><a href="#" onClick={() => this.onSetFilter(FilterType.Completed)} className={filter == FilterType.Completed ? "selected" : ""}>Completed</a></li>
|
||||
</ul>
|
||||
<button className="clear-completed" onClick={this.onClearCompleted}>Clear completed</button>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import { reactive } from 'satcheljs-react';
|
||||
import store from '../store/store';
|
||||
import addItem from '../actions/addItem';
|
||||
import updateTextboxValue from '../actions/updateTextboxValue';
|
||||
|
||||
interface HeaderProps {
|
||||
textboxValue?: string;
|
||||
}
|
||||
|
||||
@reactive({
|
||||
textboxValue: () => store.textboxValue,
|
||||
})
|
||||
export default class Header extends React.Component<HeaderProps, {}> {
|
||||
private textbox: HTMLInputElement;
|
||||
|
||||
onKeyPress = (e) => {
|
||||
if (e.key == "Enter") {
|
||||
addItem(this.textbox.value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
onChange = () => {
|
||||
// Update the store every time the textbox value changes
|
||||
updateTextboxValue(this.textbox.value);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<header className="header">
|
||||
<h1>todos</h1>
|
||||
<input
|
||||
ref={ref => this.textbox = ref}
|
||||
className="new-todo"
|
||||
placeholder="What needs to be done?"
|
||||
value={this.props.textboxValue}
|
||||
autoFocus={true}
|
||||
onChange={this.onChange}
|
||||
onKeyPress={this.onKeyPress} />
|
||||
</header>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -31,7 +31,6 @@ export default class Main extends React.Component<any, any> {
|
|||
}
|
||||
|
||||
onToggleEdit = (id: string) => {
|
||||
let inputElement = this.refs["edit_" + id] as HTMLInputElement;
|
||||
toggleEditItem(id);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import * as React from 'react';
|
||||
import { reactive } from 'satcheljs-react';
|
||||
import { FilterType } from '../../store/schema';
|
||||
import store from '../../store/store';
|
||||
import setFilter from '../../actions/setFilter';
|
||||
|
||||
interface FilterButtonProps {
|
||||
filter: FilterType;
|
||||
text: string;
|
||||
currentFilter?: FilterType;
|
||||
}
|
||||
|
||||
export default reactive({
|
||||
currentFilter: () => store.filter
|
||||
})(
|
||||
function FilterButton(props: FilterButtonProps) {
|
||||
return (
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
onClick={() => setFilter(props.filter)}
|
||||
className={props.currentFilter == props.filter ? "selected" : ""}
|
||||
>
|
||||
{props.text}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
import * as React from 'react';
|
||||
import removeAllCompleted from '../../actions/removeAllCompleted';
|
||||
import { FilterType } from '../../store/schema';
|
||||
import ItemsLeftCount from './ItemsLeftCount';
|
||||
import FilterButton from './FilterButton';
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className="footer">
|
||||
<ItemsLeftCount />
|
||||
<ul className="filters">
|
||||
<FilterButton filter={FilterType.All} text="All" />
|
||||
<FilterButton filter={FilterType.Active} text="Active" />
|
||||
<FilterButton filter={FilterType.Completed} text="Completed" />
|
||||
</ul>
|
||||
<button className="clear-completed" onClick={removeAllCompleted}>Clear completed</button>
|
||||
</footer>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import * as React from 'react';
|
||||
import { reactive } from 'satcheljs-react';
|
||||
import store from '../../store/store';
|
||||
|
||||
interface ItemsLeftCountProps {
|
||||
itemsLeft?: number;
|
||||
}
|
||||
|
||||
export default reactive({
|
||||
itemsLeft: () => store.itemsLeft
|
||||
})(
|
||||
function ItemsLeftCount(props: ItemsLeftCountProps) {
|
||||
return (
|
||||
<span className="todo-count">{props.itemsLeft} Left</span>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
import * as React from 'react';
|
||||
import NewTaskInput from './NewTaskInput';
|
||||
|
||||
export default function Header() {
|
||||
return (
|
||||
<header className="header">
|
||||
<h1>todos</h1>
|
||||
<NewTaskInput />
|
||||
</header>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
import * as React from 'react';
|
||||
import { reactive } from 'satcheljs-react';
|
||||
import store from '../../store/store';
|
||||
import addItem from '../../actions/addItem';
|
||||
import updateTextboxValue from '../../actions/updateTextboxValue';
|
||||
|
||||
interface NewTaskInputProps {
|
||||
textboxValue?: string;
|
||||
}
|
||||
|
||||
@reactive({
|
||||
textboxValue: () => store.textboxValue,
|
||||
})
|
||||
export default class NewTaskInput extends React.Component<NewTaskInputProps, {}> {
|
||||
private textbox: HTMLInputElement;
|
||||
|
||||
onKeyPress = (e) => {
|
||||
if (e.key == "Enter") {
|
||||
addItem(this.textbox.value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
onChange = () => {
|
||||
// Update the store every time the textbox value changes
|
||||
updateTextboxValue(this.textbox.value);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<input
|
||||
ref={ref => this.textbox = ref}
|
||||
className="new-todo"
|
||||
placeholder="What needs to be done?"
|
||||
value={this.props.textboxValue}
|
||||
autoFocus={true}
|
||||
onChange={this.onChange}
|
||||
onKeyPress={this.onKeyPress} />
|
||||
)
|
||||
}
|
||||
}
|
|
@ -6,7 +6,8 @@
|
|||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"outDir": "dist"
|
||||
"outDir": "dist",
|
||||
"noUnusedLocals": true
|
||||
},
|
||||
"compileOnSave": false,
|
||||
"exclude": [
|
||||
|
|
Загрузка…
Ссылка в новой задаче