animate add todo/filter selector

This commit is contained in:
2018-07-13 22:38:13 +03:00
parent 5cfb9673b0
commit e3e1efa521
14 changed files with 284 additions and 114 deletions

View File

@@ -53,7 +53,6 @@
}
#inputs {
transition: 0.4s ease-in-out;
box-shadow: 0 2px 7px rgba(0, 0, 0, 0.1);
display: flex;
height: 2.5rem;

View File

@@ -6,7 +6,7 @@ import CssBaseline from '@material-ui/core/CssBaseline';
import './Container.css';
import './App.css';
import TodosContainer from '../containers/TodosContainer';
import MainViewContainer from '../containers/MainViewContainer';
import LoginForm from './user/LoginForm';
import SignupForm from './user/SignupForm';
@@ -22,7 +22,7 @@ export default class App extends React.PureComponent {
<CssBaseline />
<Router>
<div id="container">
<Route exact path="/" component={TodosContainer} />
<Route exact path="/" component={MainViewContainer} />
<Route path="/login" component={LoginForm} />
<Route path="/signup" component={SignupForm} />
</div>

View File

@@ -2,9 +2,9 @@ import React from 'react';
import FilterLink from '../containers/FilterLink';
import { VisibilityFilters } from '../actions/defs';
function Filters() {
function Filters(styles) {
return (
<div id="filters">
<div style={styles} id="filters">
<FilterLink filter={VisibilityFilters.SHOW_ALL}>all</FilterLink>
<FilterLink filter={VisibilityFilters.SHOW_ACTIVE}>active</FilterLink>
<FilterLink filter={VisibilityFilters.SHOW_COMPLETED}>

View File

@@ -3,18 +3,18 @@ import PropTypes from 'prop-types';
import { Button } from '@material-ui/core';
import AddIcon from '@material-ui/icons/Add';
function Input(props) {
function Input({ onClick, styles }) {
let input;
function submit() {
if (input.value.trim() !== '') {
props.onClick(input.value);
onClick(input.value);
}
input.value = '';
}
return (
<div id="inputs">
<div style={styles} id="inputs">
<input
ref={node => {
input = node;
@@ -36,6 +36,7 @@ function Input(props) {
}
Input.propTypes = {
styles: PropTypes.any.isRequired,
onClick: PropTypes.func.isRequired,
};

View File

@@ -0,0 +1,21 @@
import React from 'react';
import PropTypes from 'prop-types';
import TodosContainer from '../containers/TodosContainer';
export default class MainView extends React.PureComponent {
componentDidUpdate() {
const { user, history } = this.props;
if (!user.user && !user.dirty) {
history.replace('/login');
}
}
render() {
return <TodosContainer />;
}
}
MainView.propTypes = {
user: PropTypes.any.isRequired,
history: PropTypes.any.isRequired,
};

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { Select, MenuItem } from '@material-ui/core';
import AddIcon from '@material-ui/icons/Add';
import CheckIcon from '@material-ui/icons/Check';
import { Spring, animated } from 'react-spring';
import { Transition, animated } from 'react-spring';
import './Selector.css';
@@ -28,65 +28,83 @@ export default function Selector({
if (creating) {
let input = null;
return (
<div id="listselector" className="list--input">
<input
ref={node => {
input = node;
}}
id="input"
type="text"
onKeyPress={e => {
if (e.key === 'Enter') {
addList(input.value);
}
}}
/>
<Spring native from={{ opacity: 0 }} to={{ opacity: 1 }}>
{styles => (
<Transition
native
from={{ opacity: 0, maxHeight: 0 }}
enter={{ opacity: 1, maxHeight: 64 }}
leave={{ opacity: 0, maxHeight: 0 }}
>
{styles => (
<animated.div
style={styles}
id="listselector"
className="list--input"
>
<input
ref={node => {
input = node;
}}
id="input"
type="text"
onKeyPress={e => {
if (e.key === 'Enter') {
addList(input.value);
}
}}
/>
<animated.button
style={{ ...button, ...styles }}
onClick={() => input.value.trim() && addList(input.value)}
>
<AddIcon style={icon} />
</animated.button>
)}
</Spring>
</div>
</animated.div>
)}
</Transition>
);
}
if (editing) {
let input = null;
return (
<div id="listselector" className="list--input">
<input
ref={node => {
input = node;
}}
defaultValue={lists.lists[list].name}
id="input"
type="text"
onKeyPress={e => {
if (e.key === 'Enter') {
editList(input.value);
}
}}
/>
<Spring native from={{ opacity: 0 }} to={{ opacity: 1 }}>
{styles => (
<Transition
native
from={{ opacity: 0, maxHeight: 0 }}
enter={{ opacity: 1, maxHeight: 64 }}
leave={{ opacity: 0, maxHeight: 0 }}
>
{styles => (
<animated.div
style={styles}
id="listselector"
className="list--input"
>
<input
ref={node => {
input = node;
}}
defaultValue={lists.lists[list].name}
id="input"
type="text"
onKeyPress={e => {
if (e.key === 'Enter') {
editList(input.value);
}
}}
/>
<animated.button
style={{ ...button, ...styles }}
style={{ ...button }}
onClick={() => input.value.trim() && editList(input.value)}
>
<CheckIcon style={icon} />
</animated.button>
)}
</Spring>
</div>
</animated.div>
)}
</Transition>
);
}
if (list) {
return (
<div id="listselector">
<animated.div id="listselector">
<Select
style={{ fontSize: '1.5rem', width: '100%' }}
value={list}
@@ -98,7 +116,7 @@ export default function Selector({
</MenuItem>
))}
</Select>
</div>
</animated.div>
);
}
return null;

View File

@@ -1,32 +1,35 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Transition } from 'react-spring';
import InputContainer from '../containers/InputContainer';
import TodoListContainer from '../containers/TodoListContainer';
import Header from './Header';
import Filters from './Filters';
export default class Todos extends React.PureComponent {
componentDidUpdate() {
const { user, history } = this.props;
if (!user.user && !user.dirty) {
history.replace('/login');
}
}
render() {
return (
<div id="todos">
<Header />
<InputContainer />
<TodoListContainer />
<Filters />
</div>
);
}
export default function Todos({ list }) {
return (
<div id="todos">
<Header />
<Transition
from={{ opacity: 0, maxHeight: 0 }}
enter={{ opacity: 1, maxHeight: 38 }}
leave={{ opacity: 0, maxHeight: 0 }}
>
{list && (styles => <InputContainer styles={styles} />)}
</Transition>
<TodoListContainer />
<Transition
from={{ opacity: 0, maxHeight: 0 }}
enter={{ opacity: 1, maxHeight: 32 }}
leave={{ opacity: 0, maxHeight: 0 }}
>
{list && Filters}
</Transition>
</div>
);
}
Todos.propTypes = {
history: PropTypes.object.isRequired,
user: PropTypes.object.isRequired,
list: PropTypes.bool.isRequired,
};

View File

@@ -3,6 +3,10 @@ import { connect } from 'react-redux';
import Input from '../components/Input';
import { addTodo } from '../actions/todos';
function mapStateToProps(state, ownProps) {
return { ...ownProps };
}
function mapDispatchToProps(dispatch) {
return {
onClick: text => dispatch(addTodo(text)),
@@ -10,6 +14,6 @@ function mapDispatchToProps(dispatch) {
}
export default connect(
null,
mapStateToProps,
mapDispatchToProps,
)(Input);

View File

@@ -0,0 +1,12 @@
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import MainView from '../components/MainView';
function mapStateToProps(state) {
return {
user: state.user,
};
}
export default withRouter(connect(mapStateToProps)(MainView));

View File

@@ -1,12 +1,11 @@
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import Todos from '../components/Todos';
function mapStateToProps(state) {
return {
user: state.user,
list: Boolean(state.lists.list),
};
}
export default withRouter(connect(mapStateToProps)(Todos));
export default connect(mapStateToProps)(Todos);