"redux todo app"
Bootstrap 3.0.0 Snippet by evarevirus

<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script> <script src="//code.jquery.com/jquery-1.11.1.min.js"></script> <!------ Include the above in your HEAD tag ----------> <!DOCTYPE html><html class=''> <head><script src='//production-assets.codepen.io/assets/editor/live/console_runner-079c09a0e3b9ff743e39ee2d5637b9216b3545af0de366d4b9aad9dc87e26bfd.js'></script><script src='//production-assets.codepen.io/assets/editor/live/events_runner-73716630c22bbc8cff4bd0f07b135f00a0bdc5d14629260c3ec49e5606f98fdd.js'></script><script src='//production-assets.codepen.io/assets/editor/live/css_live_reload_init-2c0dc5167d60a5af3ee189d570b1835129687ea2a61bee3513dee3a50c115a77.js'></script><meta charset='UTF-8'><meta name="robots" content="noindex"><link rel="shortcut icon" type="image/x-icon" href="//production-assets.codepen.io/assets/favicon/favicon-8ea04875e70c4b0bb41da869e81236e54394d63638a1ef12fa558a4a835f1164.ico" /><link rel="mask-icon" type="" href="//production-assets.codepen.io/assets/favicon/logo-pin-f2d2b6d2c61838f7e76325261b7195c27224080bc099486ddd6dccb469b8e8e6.svg" color="#111" /><link rel="canonical" href="https://codepen.io/subpopular/pen/rxdrXz?depth=everything&order=popularity&page=14&q=redux&show_forks=false" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel='stylesheet prefetch' href='https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css'><link rel='stylesheet prefetch' href='//fonts.googleapis.com/icon?family=Material+Icons'> <style class="cp-pen-styles">* { box-sizing: border-box; } body { font-family: sans-serif; font-size: 16px; line-height: 24px; background: #EEE; minHeight: 100vh; display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center; } button { display: inline-block; border: 0; background: #333; margin: 0; color: #FFF; height: 36px; padding: 0 12px; text-transform: uppercase; font-size: 16px; line-height: 24px; border-radius: 3px; outline: none; } .material-icons { background: transparent; color: #000; padding: 8px; height: auto; border-radius: 50%; } .material-icons:hover { background: rgba(0, 0, 0, 0.1); } .TodoApp { width: 600px; margin: 60px; display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-orient: vertical; -webkit-box-direction: normal; -ms-flex-direction: column; flex-direction: column; } .TodoApp__filters { display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center; padding: 16px; background: transparent; } .TodoApp__filter__btn, .TodoApp__filter__btn--active { background: transparent; color: #999; text-transform: none; font-size: 14px; padding: 0; width: 90px; height: auto; border: 1px solid #999; } .TodoApp__filter__btn:nth-child(1), .TodoApp__filter__btn--active:nth-child(1) { border-radius: 3px 0 0 3px; border-right: 0; } .TodoApp__filter__btn:nth-child(2), .TodoApp__filter__btn--active:nth-child(2) { border-radius: 0; border-right: 0; } .TodoApp__filter__btn:nth-child(3), .TodoApp__filter__btn--active:nth-child(3) { border-radius: 0 3px 3px 0; } .TodoApp__filter__btn--active { background: #999; color: #FFF; } .TodoApp__form { display: -webkit-box; display: -ms-flexbox; display: flex; margin-bottom: 0px; z-index: 9; position: relative; } .TodoApp__form__input { border: 0; -webkit-box-flex: 1; -ms-flex: 1; flex: 1; padding: 24px 16px; display: block; font-size: 24px; outline: none; background: #FFF; box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1); } .TodoApp__form__add-btn { height: auto; padding: 0 24px; margin-left: 8px; } .TodoApp__todo, .TodoApp__todo--completed { background: #fdfdfd; display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-pack: justify; -ms-flex-pack: justify; justify-content: space-between; -webkit-box-align: center; -ms-flex-align: center; align-items: center; padding: 16px 12px; box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.15); } .TodoApp__todo + .TodoApp__todo, .TodoApp__todo--completed + .TodoApp__todo, .TodoApp__todo + .TodoApp__todo--completed, .TodoApp__todo--completed + .TodoApp__todo--completed { border-top: 1px solid #EEE; } .TodoApp__todo.editing, .editing.TodoApp__todo--completed { padding: 0; } .TodoApp__todo:hover .TodoApp__todo__delete-btn, .TodoApp__todo--completed:hover .TodoApp__todo__delete-btn { opacity: 1; } .TodoApp__todo--completed .TodoApp__todo__complete-btn { color: green; } .TodoApp__todo__edit-input { padding: 20px 24px 22px 24px; font-size: 20px; line-height: 24px; margin: 0 0 0 0px; width: 100%; font-weight: 300; background: #FFF9C4; border: 0; outline: none; } .TodoApp__todo__label { font-size: 20px; margin: 0 12px; color: #333; font-weight: 300; } .TodoApp__todo--completed .TodoApp__todo__label { color: #CCC; text-decoration: line-through; } .TodoApp__todo__primary { display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-flex: 1; -ms-flex: 1; flex: 1; -webkit-box-align: center; -ms-flex-align: center; align-items: center; } .TodoApp__todo__complete-btn { border: 1px solid #CCC; padding: 4px; color: transparent; } .TodoApp__todo__complete-btn:hover { background: transparent; } .editing .TodoApp__todo__complete-btn { display: none; } .TodoApp__todo__delete-btn { -webkit-transition: all .1s ease-out; transition: all .1s ease-out; padding: 4px; color: #777; opacity: 0; } .TodoApp__todo__delete-btn:hover { background: transparent; color: red; } .editing .TodoApp__todo__delete-btn { display: none; } ::-webkit-input-placeholder { font-weight: 100; color: #BBB; } ::-moz-placeholder { /* Firefox 19+ */ font-weight: 100; color: #BBB; } </style></head><body> <div id="root"></div> <script src='//production-assets.codepen.io/assets/common/stopExecutionOnTimeout-b2a7b3fe212eaa732349046d8416e00a9dec26eb7fd347590fbced3ab38af52e.js'></script><script src='https://codepen.io/chriscoyier/pen/yIgqi.js'></script><script src='https://cdnjs.cloudflare.com/ajax/libs/react/0.14.6/react.min.js'></script><script src='https://cdnjs.cloudflare.com/ajax/libs/react/0.14.6/react-dom.min.js'></script><script src='https://cdnjs.cloudflare.com/ajax/libs/redux/3.0.6/redux.min.js'></script><script src='https://cdnjs.cloudflare.com/ajax/libs/react-redux/4.0.6/react-redux.min.js'></script><script src='https://cdnjs.cloudflare.com/ajax/libs/immutable/3.7.6/immutable.min.js'></script> <script >'use strict'; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var _Immutable = Immutable; var Map = _Immutable.Map; var List = _Immutable.List; var fromJS = _Immutable.fromJS; var _React = React; var Component = _React.Component; var _Redux = Redux; var createStore = _Redux.createStore; var combineReducers = _Redux.combineReducers; var initialState = { todos: [], visibilityFilter: 'SHOW_ALL' }; /** * * REDUCERS * */ var addTodo = function addTodo(state, action) { var todos = state.get('todos'); var newTodo = fromJS({ id: getTodoId(todos), text: action.text, completed: false }); return state.set('todos', todos.push(newTodo)); }; var deleteTodo = function deleteTodo(state, action) { var todoIndex = state.get('todos').findIndex(function (t) { return t.get('id') === action.id; }); return state.deleteIn(['todos', todoIndex]); }; var editTodo = function editTodo(state, action) { var todos = state.get('todos'); var todoIndex = todos.findIndex(function (t) { return t.get('id') === action.id; }); return state.setIn(['todos', todoIndex, 'text'], action.text); }; var toggleTodo = function toggleTodo(state, action) { var todos = state.get('todos'); var _todos$findEntry = todos.findEntry(function (t) { return t.get('id') === action.id; }); var todoIndex = _todos$findEntry[0]; var todo = _todos$findEntry[1]; return state.setIn(['todos', todoIndex], todo.set('completed', !todo.get('completed'))); }; var setFilter = function setFilter(state, action) { return action.filter ? state.set('visibilityFilter', action.filter) : state; }; var todoList = function todoList() { var state = arguments.length <= 0 || arguments[0] === undefined ? initialState : arguments[0]; var action = arguments[1]; if (!Map.isMap(state) && !List.isList(state)) state = Immutable.fromJS(state); var handlers = { ADD_TODO: addTodo, DELETE_TODO: deleteTodo, EDIT_TODO: editTodo, TOGGLE_TODO: toggleTodo, SET_FILTER: setFilter }; return handlers[action.type] ? handlers[action.type](state, action) : state; }; /** * * COMPONENTS * */ var Todo = function Todo(_ref) { var todo = _ref.todo; var editing = _ref.editing; var todoEditInputRef = _ref.todoEditInputRef; var toggleTodo = _ref.toggleTodo; var beginEditing = _ref.beginEditing; var endEditing = _ref.endEditing; var deleteTodo = _ref.deleteTodo; return React.createElement( 'div', { className: (!todo.completed ? 'TodoApp__todo' : 'TodoApp__todo--completed') + (editing ? ' editing' : ''), onDoubleClick: function onDoubleClick(e) { return beginEditing(todo.id); } }, React.createElement( 'div', { className: 'TodoApp__todo__primary' }, React.createElement( 'button', { className: 'material-icons TodoApp__todo__complete-btn', onClick: function onClick() { return toggleTodo(todo.id); } }, 'done' ), editing ? React.createElement('input', { className: 'TodoApp__todo__edit-input', ref: todoEditInputRef, onKeyUp: function onKeyUp(e) { if (e.keyCode === 13) endEditing(todo.id); }, onBlur: function onBlur(e) { return endEditing(todo.id); }, defaultValue: todo.text }) : React.createElement( 'div', { className: 'TodoApp__todo__label' }, todo.text ) ), React.createElement( 'button', { className: 'material-icons TodoApp__todo__delete-btn', onClick: function onClick() { return deleteTodo(todo.id); } }, 'close' ) ); }; var VisibilityFilterButton = function VisibilityFilterButton(_ref2) { var filter = _ref2.filter; var label = _ref2.label; var active = _ref2.active; var setFilter = _ref2.setFilter; return React.createElement( 'button', { className: active(filter) ? 'TodoApp__filter__btn--active' : 'TodoApp__filter__btn', onClick: function onClick() { return setFilter(filter); } }, label ); }; var TodoApp = function (_Component) { _inherits(TodoApp, _Component); function TodoApp(props) { _classCallCheck(this, TodoApp); var _this = _possibleConstructorReturn(this, _Component.call(this, props)); _this.state = { editing: null }; return _this; } TodoApp.prototype.render = function render() { var _this2 = this; var _props$store$getState = this.props.store.getState().todoList.toJS(); var todos = _props$store$getState.todos; var visibilityFilter = _props$store$getState.visibilityFilter; var filteredTodos = todos.filter(function (t) { if (visibilityFilter === 'SHOW_ACTIVE') return !t.completed; if (visibilityFilter === 'SHOW_COMPLETED') return t.completed; return true; }); return React.createElement( 'div', { className: 'TodoApp' }, React.createElement( 'div', { className: 'TodoApp__filters' }, React.createElement(VisibilityFilterButton, { filter: 'SHOW_ALL', label: 'All', active: function active(f) { return visibilityFilter === f; }, setFilter: function setFilter(f) { return _this2.setFilter(f); } }), React.createElement(VisibilityFilterButton, { filter: 'SHOW_ACTIVE', label: 'Active', active: function active(f) { return visibilityFilter === f; }, setFilter: function setFilter(f) { return _this2.setFilter(f); } }), React.createElement(VisibilityFilterButton, { filter: 'SHOW_COMPLETED', label: 'Complete', active: function active(f) { return visibilityFilter === f; }, setFilter: function setFilter(f) { return _this2.setFilter(f); } }) ), React.createElement( 'div', { className: 'TodoApp__form' }, React.createElement('input', { className: 'TodoApp__form__input', ref: function ref(node) { return _this2.input = node; }, placeholder: 'Add a todo...', onKeyUp: function onKeyUp(e) { return _this2.handleKeyUp(e); } }) ), React.createElement( 'div', { className: 'TodoApp__todo-list' }, filteredTodos.map(function (todo) { return React.createElement(Todo, { todo: todo, editing: _this2.state.editing === todo.id, todoEditInputRef: function todoEditInputRef(node) { return _this2.todoEditInput = node; }, toggleTodo: function toggleTodo(id) { return _this2.toggleTodo(id); }, beginEditing: function beginEditing(id) { return _this2.beginEditing(id); }, endEditing: function endEditing(id) { return _this2.endEditing(id); }, deleteTodo: function deleteTodo(id) { return _this2.deleteTodo(id); } }); }) ) ); }; TodoApp.prototype.addTodo = function addTodo() { if (!this.input.value) return; this.props.store.dispatch({ type: 'ADD_TODO', text: this.input.value }); this.input.value = ''; }; TodoApp.prototype.toggleTodo = function toggleTodo(id) { this.props.store.dispatch({ type: 'TOGGLE_TODO', id: id }); }; TodoApp.prototype.deleteTodo = function deleteTodo(id) { this.props.store.dispatch({ type: 'DELETE_TODO', id: id }); }; TodoApp.prototype.setFilter = function setFilter(filter) { this.props.store.dispatch({ type: 'SET_FILTER', filter: filter }); }; TodoApp.prototype.handleKeyUp = function handleKeyUp(e) { if (e.keyCode === 13) this.addTodo(); }; TodoApp.prototype.beginEditing = function beginEditing(id) { var _this3 = this; this.setState({ editing: id }, function () { var node = _this3.todoEditInput; node.focus(); node.setSelectionRange(node.value.length, node.value.length); }); }; TodoApp.prototype.endEditing = function endEditing(id) { this.setState({ editing: null }); if (!this.todoEditInput.value) return; this.props.store.dispatch({ type: 'EDIT_TODO', text: this.todoEditInput.value, id: id }); }; return TodoApp; }(Component); /** * * INIT APP * */ var todoApp = combineReducers({ todoList: todoList }); var store = createStore(todoApp); var render = function render() { ReactDOM.render(React.createElement(TodoApp, { store: store }), document.getElementById('root')); }; render(); store.subscribe(render); /** * * HELPERS * */ function getTodoId(todos) { var _Math; return todos.size ? (_Math = Math).max.apply(_Math, todos.map(function (t) { return t.get('id'); }).toJS()) + 1 : 0; } //# sourceURL=pen.js </script> </body></html>

Related: See More


Questions / Comments: