mirror of
https://github.com/usatiuk/ustk-todolist.git
synced 2025-10-28 23:57:49 +01:00
animations
This commit is contained in:
54
package-lock.json
generated
54
package-lock.json
generated
@@ -4,6 +4,22 @@
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.0.0-beta.49",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.49.tgz",
|
||||
"integrity": "sha1-A7O/B+uYIHLI6FHdLd1RECguYb8=",
|
||||
"requires": {
|
||||
"core-js": "2.5.7",
|
||||
"regenerator-runtime": "0.11.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": {
|
||||
"version": "2.5.7",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
|
||||
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@fortawesome/fontawesome-common-types": {
|
||||
"version": "0.2.0-8",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.0-8.tgz",
|
||||
@@ -3252,9 +3268,9 @@
|
||||
}
|
||||
},
|
||||
"eslint-plugin-import": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.11.0.tgz",
|
||||
"integrity": "sha1-Fa7qN6Z0mdhI6OmBgG1GJ7VQOBY=",
|
||||
"version": "2.12.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.12.0.tgz",
|
||||
"integrity": "sha1-2tMXgSktZmSyUxf9BJ0uKy8CIF0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"contains-path": "0.1.0",
|
||||
@@ -3330,9 +3346,9 @@
|
||||
}
|
||||
},
|
||||
"eslint-plugin-jest": {
|
||||
"version": "21.15.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-21.15.2.tgz",
|
||||
"integrity": "sha512-XX0/g2F2iDnX36Ez4j5Sd8IzJj2dbDBqOxitfGD+uXyiEVECJAoRnf9eQnkzyXFVKB7DALx82ZqgqCEfeLpY7w==",
|
||||
"version": "21.16.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-21.16.0.tgz",
|
||||
"integrity": "sha512-pyhIbWj9RyT48q3e4A2WWec+ovn43Un3oeYIPQ1erT1PTSPJhHm9DVRtr1Vuf1GbrcFfsSROaUlkSvp6tQBGqA==",
|
||||
"dev": true
|
||||
},
|
||||
"eslint-plugin-jsx-a11y": {
|
||||
@@ -3351,9 +3367,9 @@
|
||||
}
|
||||
},
|
||||
"eslint-plugin-react": {
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz",
|
||||
"integrity": "sha512-KC7Snr4YsWZD5flu6A5c0AcIZidzW3Exbqp7OT67OaD2AppJtlBr/GuPrW/vaQM/yfZotEvKAdrxrO+v8vwYJA==",
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.8.2.tgz",
|
||||
"integrity": "sha512-H3ne8ob4Bn6NXSN9N9twsn7t8dyHT5bF/ibQepxIHi6JiPIdC2gXlfYvZYucbdrWio4FxBq7Z4mSauQP+qmMkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"doctrine": "2.1.0",
|
||||
@@ -8970,9 +8986,9 @@
|
||||
}
|
||||
},
|
||||
"react": {
|
||||
"version": "16.3.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.3.2.tgz",
|
||||
"integrity": "sha512-o5GPdkhciQ3cEph6qgvYB7LTOHw/GB0qRI6ZFNugj49qJCFfgHwVNjZ5u+b7nif4vOeMIOuYj3CeYe2IBD74lg==",
|
||||
"version": "16.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.4.0.tgz",
|
||||
"integrity": "sha512-K0UrkLXSAekf5nJu89obKUM7o2vc6MMN9LYoKnCa+c+8MJRAT120xzPLENcWSRc7GYKIg0LlgJRDorrufdglQQ==",
|
||||
"requires": {
|
||||
"fbjs": "0.8.16",
|
||||
"loose-envify": "1.3.1",
|
||||
@@ -9006,9 +9022,9 @@
|
||||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"version": "16.3.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.3.2.tgz",
|
||||
"integrity": "sha512-MMPko3zYncNrz/7gG17wJWUREZDvskZHXOwbttzl0F0L3wDmToyuETuo/r8Y5yvDejwYcRyWI1lvVBjLJWFwKA==",
|
||||
"version": "16.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.0.tgz",
|
||||
"integrity": "sha512-bbLd+HYpBEnYoNyxDe9XpSG2t9wypMohwQPvKw8Hov3nF7SJiJIgK56b46zHpBUpHb06a1iEuw7G3rbrsnNL6w==",
|
||||
"requires": {
|
||||
"fbjs": "0.8.16",
|
||||
"loose-envify": "1.3.1",
|
||||
@@ -9212,6 +9228,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-spring": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/react-spring/-/react-spring-5.3.3.tgz",
|
||||
"integrity": "sha512-5iJg9UJKEcLYEwdMpxDIzEeYwp14y5BcbLw/QckkQQBP2d7W0E3N7tIxdsE8VlPtq99kNuQvgLMn8DgH1Fl9dg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "7.0.0-beta.49"
|
||||
}
|
||||
},
|
||||
"read-pkg": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
|
||||
|
||||
11
package.json
11
package.json
@@ -8,10 +8,11 @@
|
||||
"@fortawesome/react-fontawesome": "0.1.0-10",
|
||||
"normalize.css": "^8.0.0",
|
||||
"prop-types": "^15.6.1",
|
||||
"react": "^16.3.2",
|
||||
"react-dom": "^16.3.2",
|
||||
"react": "^16.4.0",
|
||||
"react-dom": "^16.4.0",
|
||||
"react-redux": "^5.0.7",
|
||||
"react-scripts": "1.1.4",
|
||||
"react-spring": "^5.3.3",
|
||||
"redux": "^4.0.0",
|
||||
"redux-thunk": "^2.2.0"
|
||||
},
|
||||
@@ -24,10 +25,10 @@
|
||||
"devDependencies": {
|
||||
"eslint-config-airbnb": "^16.1.0",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
"eslint-plugin-import": "^2.11.0",
|
||||
"eslint-plugin-jest": "^21.15.2",
|
||||
"eslint-plugin-import": "^2.12.0",
|
||||
"eslint-plugin-jest": "^21.16.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.0.3",
|
||||
"eslint-plugin-react": "^7.7.0",
|
||||
"eslint-plugin-react": "^7.8.2",
|
||||
"prettier-eslint": "^8.8.1"
|
||||
}
|
||||
}
|
||||
|
||||
61
src/App.css
61
src/App.css
@@ -91,46 +91,32 @@ li:first-child .item {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.delete {
|
||||
li button {
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 0.5rem;
|
||||
text-align: center;
|
||||
background-color: pink;
|
||||
border: none;
|
||||
border-top: 1px solid #dddddd;
|
||||
background: none;
|
||||
text-align: left;
|
||||
max-width: 2rem;
|
||||
font-size: 0.75rem;
|
||||
font-size: 1rem;
|
||||
transition: 0.3s ease-in-out;
|
||||
overflow: hidden;
|
||||
box-shadow: inset -3px 0 6px -3px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.delete {
|
||||
background-color: pink;
|
||||
}
|
||||
|
||||
.edit {
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 0.5rem;
|
||||
text-align: center;
|
||||
background-color: lightcyan;
|
||||
border-top: 1px solid #dddddd;
|
||||
max-width: 2rem;
|
||||
font-size: 0.75rem;
|
||||
transition: 0.3s ease-in-out;
|
||||
overflow: hidden;
|
||||
box-shadow: inset -3px 0 6px -3px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.save {
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 0.5rem;
|
||||
text-align: center;
|
||||
background-color: lightgreen;
|
||||
border-top: 1px solid #dddddd;
|
||||
max-width: 2rem;
|
||||
font-size: 0.75rem;
|
||||
transition: 0.3s ease-in-out;
|
||||
overflow: hidden;
|
||||
box-shadow: inset -3px 0 6px -3px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.todo {
|
||||
@@ -145,14 +131,14 @@ li:first-child .item {
|
||||
}
|
||||
|
||||
.todo--input {
|
||||
resize: vertical;
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
max-width: 100%;
|
||||
flex-grow: 2;
|
||||
flex-shrink: 1;
|
||||
width: 100%;
|
||||
max-height: 100%;
|
||||
transition: 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
@@ -169,29 +155,6 @@ li:first-child .item {
|
||||
animation: 0.4s collapse;
|
||||
}
|
||||
|
||||
@keyframes create {
|
||||
from {
|
||||
width: 50rem;
|
||||
overflow: visible;
|
||||
position: relative;
|
||||
padding-left: 0.5rem;
|
||||
bottom: 2rem;
|
||||
max-height: 0;
|
||||
}
|
||||
to {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
bottom: 0rem;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes collapse {
|
||||
to {
|
||||
height: 0;
|
||||
max-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -10,6 +10,11 @@ function Input(props) {
|
||||
classes.push('no-border');
|
||||
}
|
||||
|
||||
function submit() {
|
||||
props.onClick(input.value);
|
||||
input.value = '';
|
||||
}
|
||||
|
||||
return (
|
||||
<div id="inputs" className={classes.join(' ')}>
|
||||
<input
|
||||
@@ -19,7 +24,7 @@ function Input(props) {
|
||||
id="input"
|
||||
type="text"
|
||||
/>
|
||||
<button id="add" onClick={() => props.onClick(input.value)}>
|
||||
<button id="add" onClick={() => submit()}>
|
||||
add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { faTrash, faEdit, faCheck } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { animated } from 'react-spring';
|
||||
|
||||
class Todo extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -61,40 +62,40 @@ class Todo extends React.Component {
|
||||
if (this.state.editing) {
|
||||
let input;
|
||||
return (
|
||||
<li>
|
||||
<div className="save" onClick={() => this.stopEdit(input.value)}>
|
||||
<animated.li style={this.props.style}>
|
||||
<button className="save" onClick={() => this.stopEdit(input.value)}>
|
||||
<FontAwesomeIcon icon={faCheck} />
|
||||
</div>
|
||||
</button>
|
||||
<div className={todoClasses.join(' ')}>
|
||||
<input
|
||||
<textarea
|
||||
className="todo--input"
|
||||
type="text"
|
||||
defaultValue={this.props.todo.text}
|
||||
ref={(node) => {
|
||||
input = node;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
</animated.li>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<li
|
||||
<animated.li
|
||||
style={this.props.style}
|
||||
onMouseOver={this.onMouseOver}
|
||||
onFocus={this.onMouseOver}
|
||||
onMouseOut={this.onMouseOut}
|
||||
onBlur={this.onMouseOut}
|
||||
>
|
||||
<div className={deleteClasses.join(' ')} onClick={this.props.removeTodo}>
|
||||
<button className={deleteClasses.join(' ')} onClick={this.props.removeTodo}>
|
||||
<FontAwesomeIcon icon={faTrash} />
|
||||
</div>
|
||||
<div className={editClasses.join(' ')} onClick={this.startEdit}>
|
||||
</button>
|
||||
<button className={editClasses.join(' ')} onClick={this.startEdit}>
|
||||
<FontAwesomeIcon icon={faEdit} />
|
||||
</div>
|
||||
<div className={todoClasses.join(' ')} onClick={this.props.toggleTodo}>
|
||||
</button>
|
||||
<button className={todoClasses.join(' ')} onClick={this.props.toggleTodo}>
|
||||
{this.props.todo.text}
|
||||
</div>
|
||||
</li>
|
||||
</button>
|
||||
</animated.li>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -108,6 +109,7 @@ Todo.propTypes = {
|
||||
removeTodo: PropTypes.func.isRequired,
|
||||
toggleTodo: PropTypes.func.isRequired,
|
||||
editTodo: PropTypes.func.isRequired,
|
||||
style: PropTypes.shape({ maxHeight: PropTypes.number.isRequired }).isRequired,
|
||||
};
|
||||
|
||||
export default Todo;
|
||||
|
||||
@@ -1,19 +1,32 @@
|
||||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Transition } from 'react-spring';
|
||||
|
||||
import Todo from './Todo';
|
||||
|
||||
export default function TodosContainer(props) {
|
||||
const todos = props.todos.map(todo => (
|
||||
const todos = props.todos.map(todo => styles => (
|
||||
<Todo
|
||||
key={todo.id}
|
||||
todo={todo}
|
||||
style={styles}
|
||||
toggleTodo={() => props.toggleTodo(todo.id)}
|
||||
removeTodo={() => props.removeTodo(todo.id)}
|
||||
editTodo={text => props.editTodo(todo.id, text)}
|
||||
/>
|
||||
));
|
||||
return <ul id="list">{todos}</ul>;
|
||||
return (
|
||||
<ul id="list">
|
||||
<Transition
|
||||
keys={props.todos.map(todo => todo.id)}
|
||||
from={{ maxHeight: 0 }}
|
||||
enter={{ maxHeight: 100 }}
|
||||
leave={{ maxHeight: 0 }}
|
||||
>
|
||||
{todos}
|
||||
</Transition>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
TodosContainer.propTypes = {
|
||||
|
||||
@@ -1,39 +1,27 @@
|
||||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Input from '../components/Input';
|
||||
import { addTodo } from '../actions';
|
||||
import getVisibleTodos from './getVisibleTodos';
|
||||
|
||||
const InputContainer = props => (
|
||||
<Input
|
||||
inputBottomBorder={props.inputBottomBorder}
|
||||
onClick={text => props.dispatch(addTodo(text))}
|
||||
/>
|
||||
);
|
||||
|
||||
InputContainer.propTypes = {
|
||||
inputBottomBorder: PropTypes.bool.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const { list } = state.lists;
|
||||
try {
|
||||
const listTodos = state.lists.lists[list].todos;
|
||||
return {
|
||||
list,
|
||||
inputBottomBorder: getVisibleTodos(listTodos, state.visibilityFilter).length !== 0,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
list,
|
||||
inputBottomBorder: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const InputContainerConnected = connect(mapStateToProps)(InputContainer);
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
onClick: text => dispatch(addTodo(text)),
|
||||
};
|
||||
}
|
||||
|
||||
export default InputContainerConnected;
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Input);
|
||||
|
||||
@@ -21,7 +21,7 @@ export default function todos(state = { dirty: true, fetching: false, todos: []
|
||||
case ADD_TODO:
|
||||
return {
|
||||
...state,
|
||||
todos: [...state.todos, action.todo],
|
||||
todos: [action.todo, ...state.todos],
|
||||
};
|
||||
case INVALIDATE_TODOS:
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user