Last active
June 30, 2020 22:53
-
-
Save toranb/4bb9c326a7e54c739b1f5a5023ccc805 to your computer and use it in GitHub Desktop.
New Twiddle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import * as types from '../actions/types'; | |
| export const addTodo = text => dispatch => dispatch({type: types.ADD_TODO, text}); | |
| export const deleteTodo = id => dispatch => dispatch({type: types.DELETE_TODO, id}); | |
| export const editTodo = (id, text) => dispatch => dispatch({type: types.EDIT_TODO, id, text}); | |
| export const completeTodo = id => dispatch => dispatch({type: types.COMPLETE_TODO, id}); | |
| export const clearCompleted = () => dispatch => dispatch({type: types.CLEAR_COMPLETED}); | |
| export const showAll = () => dispatch => dispatch({type: types.SHOW_ALL}); | |
| export const showActive = () => dispatch => dispatch({type: types.SHOW_ACTIVE}); | |
| export const showCompleted = () => dispatch => dispatch({type: types.SHOW_COMPLETED}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| export const ADD_TODO = 'ADD_TODO'; | |
| export const DELETE_TODO = 'DELETE_TODO'; | |
| export const EDIT_TODO = 'EDIT_TODO'; | |
| export const COMPLETE_TODO = 'COMPLETE_TODO'; | |
| export const CLEAR_COMPLETED = 'CLEAR_COMPLETED'; | |
| export const SHOW_ALL = 'SHOW_ALL'; | |
| export const SHOW_ACTIVE = 'SHOW_ACTIVE'; | |
| export const SHOW_COMPLETED = 'SHOW_COMPLETED'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Ember from 'ember'; | |
| import { connect } from 'ember-redux'; | |
| import { editTodo, deleteTodo, completeTodo } from '../actions/todos'; | |
| const { get, set, run: { scheduleOnce } } = Ember; | |
| const TodoItemComponent = Ember.Component.extend({ | |
| tagName: 'li', | |
| editing: false, | |
| classNameBindings: ['todo.completed', 'editing'], | |
| actions: { | |
| startEditing() { | |
| set(this, 'editing', true); | |
| }, | |
| doneEditing() { | |
| set(this, 'editing', false); | |
| }, | |
| focusInput() { | |
| scheduleOnce('afterRender', this, () => { | |
| this.element.querySelector('input.edit').focus(); | |
| }); | |
| }, | |
| handleKeydown(e) { | |
| if (e.keyCode === 13) { | |
| e.target.blur(); | |
| } else if (e.keyCode === 27) { | |
| set(this, 'editing', false); | |
| } | |
| } | |
| } | |
| }); | |
| const dispatchToActions = { | |
| deleteTodo, | |
| completeTodo, | |
| editTodo | |
| } | |
| export default connect(null, dispatchToActions)(TodoItemComponent); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Ember from 'ember'; | |
| import { connect } from 'ember-redux'; | |
| import { getTodos } from '../reducers/todos'; | |
| const TodoListComponent = Ember.Component.extend({ | |
| tagName: 'ul', | |
| classNames: 'todo-list' | |
| }); | |
| const stateToComputed = state => ({ | |
| todos: getTodos(state) | |
| }); | |
| export default connect(stateToComputed)(TodoListComponent); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Ember from 'ember'; | |
| const { get, computed } = Ember; | |
| export default Ember.Component.extend({ | |
| tagName: 'span', | |
| classNames: 'todo-count', | |
| itemWord: computed('todosCount', function() { | |
| let count = get(this, 'todosCount'); | |
| return count > 1 ? 'items' : 'item'; | |
| }) | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Ember from 'ember'; | |
| import { connect } from 'ember-redux'; | |
| import { addTodo } from '../actions/todos'; | |
| const HeaderComponent = Ember.Component.extend({ | |
| text: '', | |
| tagName: 'header', | |
| classNames: 'header' | |
| }); | |
| const dispatchToActions = { | |
| addTodo | |
| } | |
| export default connect(null, dispatchToActions)(HeaderComponent); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Ember from 'ember'; | |
| export default Ember.Component.extend({ | |
| classNames: 'todoapp' | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Ember from 'ember'; | |
| export default Ember.Component.extend({ | |
| tagName: 'section', | |
| classNames: 'main' | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Ember from 'ember'; | |
| export function gt([n1, n2]) { | |
| return n1 > n2; | |
| } | |
| export default Ember.Helper.helper(gt); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Ember from 'ember'; | |
| export default Ember.Helper.helper(function(params) { | |
| return params[0] === params[1]; | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Ember from 'ember'; | |
| export function invokeFunction(acc, curr) { | |
| return curr(acc); | |
| } | |
| export function pipe(actions = []) { | |
| return function(...args) { | |
| return actions.reduce((acc, curr, idx) => { | |
| if (idx === 0) { | |
| return curr(...args); | |
| } | |
| return invokeFunction(acc, curr); | |
| }, undefined); | |
| }; | |
| } | |
| export default Ember.Helper.helper(pipe); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { combineReducers } from 'redux' | |
| import todos from './todos' | |
| const rootReducer = combineReducers({ | |
| todos | |
| }) | |
| export default rootReducer |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import reselect from 'reselect'; | |
| import mapValues from 'lodash/mapValues'; | |
| import omitBy from 'lodash/omitBy'; | |
| import merge from 'lodash/merge'; | |
| import omit from 'lodash/omit'; | |
| import defaults from 'lodash/defaults'; | |
| import * as types from '../actions/types'; | |
| const { createSelector } = reselect; | |
| const initialState = { | |
| filter: undefined, | |
| all: { | |
| 1: { | |
| id: 1, | |
| text: 'Use Ember Redux', | |
| completed: false | |
| } | |
| } | |
| }; | |
| export default function todos(state, action) { | |
| switch (action.type) { | |
| case types.CLEAR_COMPLETED: { | |
| let todos = omitBy(state.all, todo => todo.completed === true); | |
| return Object.assign({}, state, { all: todos }); | |
| } | |
| case types.SHOW_ACTIVE: { | |
| return Object.assign({}, state, { filter: false }); | |
| } | |
| case types.SHOW_COMPLETED: { | |
| return Object.assign({}, state, { filter: true }); | |
| } | |
| case types.SHOW_ALL: { | |
| return Object.assign({}, state, { filter: undefined }); | |
| } | |
| case types.DELETE_TODO: { | |
| let todos = omit(state.all, [action.id]); | |
| return Object.assign({}, state, { all: todos }); | |
| } | |
| case types.EDIT_TODO: { | |
| let todos = mapValues(state.all, todo => { | |
| return todo.id === action.id ? defaults({ | |
| text: action.text | |
| }, todo) : todo; | |
| }); | |
| return Object.assign({}, state, { all: todos }); | |
| } | |
| case types.COMPLETE_TODO: { | |
| let todos = mapValues(state.all, todo => { | |
| return todo.id === action.id ? defaults({ | |
| completed: !todo.completed | |
| }, todo) : todo; | |
| }); | |
| return Object.assign({}, state, { all: todos }); | |
| } | |
| case types.ADD_TODO: { | |
| const id = Object.values(state.all).reduce((maxId, todo) => Math.max(todo.id, maxId), -1) + 1; | |
| let todo = { | |
| [id]: { | |
| id: id, | |
| completed: false, | |
| text: action.text | |
| } | |
| } | |
| let todos = merge({}, state.all, todo); | |
| return Object.assign({}, state, { all: todos }); | |
| } | |
| default: { | |
| return state || initialState; | |
| } | |
| } | |
| } | |
| const all = state => state.todos.all; | |
| const filter = state => state.todos.filter; | |
| export const getTodos = createSelector( | |
| all, | |
| filter, | |
| (all, filter) => { | |
| return omitBy(all, todo => { | |
| return filter === undefined ? false : filter !== todo.completed; | |
| }); | |
| } | |
| ); | |
| export const getAllTodosCount = createSelector(all, (all) => Object.values(all).length); | |
| export const getFilter = createSelector(filter, filter => filter); | |
| export const getTodosCount = createSelector(getTodos, (todos) => Object.values(todos).length); | |
| export const getCompletedCount = createSelector(all, (all) => Object.values(all).filter(t => t.completed).length); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| html, | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| } | |
| button { | |
| margin: 0; | |
| padding: 0; | |
| border: 0; | |
| background: none; | |
| font-size: 100%; | |
| vertical-align: baseline; | |
| font-family: inherit; | |
| font-weight: inherit; | |
| color: inherit; | |
| -webkit-appearance: none; | |
| appearance: none; | |
| -webkit-font-smoothing: antialiased; | |
| -moz-osx-font-smoothing: grayscale; | |
| } | |
| body { | |
| font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; | |
| line-height: 1.4em; | |
| background: #f5f5f5; | |
| color: #4d4d4d; | |
| min-width: 230px; | |
| max-width: 550px; | |
| margin: 0 auto; | |
| -webkit-font-smoothing: antialiased; | |
| -moz-osx-font-smoothing: grayscale; | |
| font-weight: 300; | |
| } | |
| :focus { | |
| outline: 0; | |
| } | |
| .hidden { | |
| display: none; | |
| } | |
| .todoapp { | |
| background: #fff; | |
| margin: 130px 0 40px 0; | |
| position: relative; | |
| box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), | |
| 0 25px 50px 0 rgba(0, 0, 0, 0.1); | |
| } | |
| .todoapp input::-webkit-input-placeholder { | |
| font-style: italic; | |
| font-weight: 300; | |
| color: #e6e6e6; | |
| } | |
| .todoapp input::-moz-placeholder { | |
| font-style: italic; | |
| font-weight: 300; | |
| color: #e6e6e6; | |
| } | |
| .todoapp input::input-placeholder { | |
| font-style: italic; | |
| font-weight: 300; | |
| color: #e6e6e6; | |
| } | |
| .todoapp h1 { | |
| position: absolute; | |
| top: -155px; | |
| width: 100%; | |
| font-size: 100px; | |
| font-weight: 100; | |
| text-align: center; | |
| color: rgba(175, 47, 47, 0.15); | |
| -webkit-text-rendering: optimizeLegibility; | |
| -moz-text-rendering: optimizeLegibility; | |
| text-rendering: optimizeLegibility; | |
| } | |
| .new-todo, | |
| .edit { | |
| position: relative; | |
| margin: 0; | |
| width: 100%; | |
| font-size: 24px; | |
| font-family: inherit; | |
| font-weight: inherit; | |
| line-height: 1.4em; | |
| border: 0; | |
| color: inherit; | |
| padding: 6px; | |
| border: 1px solid #999; | |
| box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); | |
| box-sizing: border-box; | |
| -webkit-font-smoothing: antialiased; | |
| -moz-osx-font-smoothing: grayscale; | |
| } | |
| .new-todo { | |
| padding: 16px 16px 16px 60px; | |
| border: none; | |
| background: rgba(0, 0, 0, 0.003); | |
| box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03); | |
| } | |
| .main { | |
| position: relative; | |
| z-index: 2; | |
| border-top: 1px solid #e6e6e6; | |
| } | |
| .toggle-all { | |
| text-align: center; | |
| border: none; /* Mobile Safari */ | |
| opacity: 0; | |
| position: absolute; | |
| } | |
| .toggle-all + label { | |
| width: 60px; | |
| height: 34px; | |
| font-size: 0; | |
| position: absolute; | |
| top: -52px; | |
| left: -13px; | |
| -webkit-transform: rotate(90deg); | |
| transform: rotate(90deg); | |
| } | |
| .toggle-all + label:before { | |
| content: '❯'; | |
| font-size: 22px; | |
| color: #e6e6e6; | |
| padding: 10px 27px 10px 27px; | |
| } | |
| .toggle-all:checked + label:before { | |
| color: #737373; | |
| } | |
| .todo-list { | |
| margin: 0; | |
| padding: 0; | |
| list-style: none; | |
| } | |
| .todo-list li { | |
| position: relative; | |
| font-size: 24px; | |
| border-bottom: 1px solid #ededed; | |
| } | |
| .todo-list li:last-child { | |
| border-bottom: none; | |
| } | |
| .todo-list li.editing { | |
| border-bottom: none; | |
| padding: 0; | |
| } | |
| .todo-list li.editing .edit { | |
| display: block; | |
| width: 506px; | |
| padding: 12px 16px; | |
| margin: 0 0 0 43px; | |
| } | |
| .todo-list li.editing .view { | |
| display: none; | |
| } | |
| .todo-list li .toggle { | |
| text-align: center; | |
| width: 40px; | |
| /* auto, since non-WebKit browsers doesn't support input styling */ | |
| height: auto; | |
| position: absolute; | |
| top: 0; | |
| bottom: 0; | |
| margin: auto 0; | |
| border: none; /* Mobile Safari */ | |
| -webkit-appearance: none; | |
| appearance: none; | |
| } | |
| .todo-list li .toggle { | |
| opacity: 0; | |
| } | |
| .todo-list li .toggle + label { | |
| /* | |
| Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433 | |
| IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/ | |
| */ | |
| background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E'); | |
| background-repeat: no-repeat; | |
| background-position: center left; | |
| } | |
| .todo-list li .toggle:checked + label { | |
| background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E'); | |
| } | |
| .todo-list li label { | |
| word-break: break-all; | |
| padding: 15px 15px 15px 60px; | |
| display: block; | |
| line-height: 1.2; | |
| transition: color 0.4s; | |
| } | |
| .todo-list li.completed label { | |
| color: #d9d9d9; | |
| text-decoration: line-through; | |
| } | |
| .todo-list li .destroy { | |
| display: none; | |
| position: absolute; | |
| top: 0; | |
| right: 10px; | |
| bottom: 0; | |
| width: 40px; | |
| height: 40px; | |
| margin: auto 0; | |
| font-size: 30px; | |
| color: #cc9a9a; | |
| margin-bottom: 11px; | |
| transition: color 0.2s ease-out; | |
| } | |
| .todo-list li .destroy:hover { | |
| color: #af5b5e; | |
| } | |
| .todo-list li .destroy:after { | |
| content: '×'; | |
| } | |
| .todo-list li:hover .destroy { | |
| display: block; | |
| } | |
| .todo-list li .edit { | |
| display: none; | |
| } | |
| .todo-list li.editing:last-child { | |
| margin-bottom: -1px; | |
| } | |
| .footer { | |
| color: #777; | |
| padding: 10px 15px; | |
| height: 20px; | |
| text-align: center; | |
| border-top: 1px solid #e6e6e6; | |
| } | |
| .footer:before { | |
| content: ''; | |
| position: absolute; | |
| right: 0; | |
| bottom: 0; | |
| left: 0; | |
| height: 50px; | |
| overflow: hidden; | |
| box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), | |
| 0 8px 0 -3px #f6f6f6, | |
| 0 9px 1px -3px rgba(0, 0, 0, 0.2), | |
| 0 16px 0 -6px #f6f6f6, | |
| 0 17px 2px -6px rgba(0, 0, 0, 0.2); | |
| } | |
| .todo-count { | |
| float: left; | |
| text-align: left; | |
| } | |
| .todo-count strong { | |
| font-weight: 300; | |
| } | |
| .filters { | |
| margin: 0; | |
| padding: 0; | |
| list-style: none; | |
| position: absolute; | |
| right: 0; | |
| left: 0; | |
| } | |
| .filters li { | |
| display: inline; | |
| } | |
| .filters li a { | |
| color: inherit; | |
| margin: 3px; | |
| padding: 3px 7px; | |
| text-decoration: none; | |
| border: 1px solid transparent; | |
| border-radius: 3px; | |
| } | |
| .filters li a:hover { | |
| border-color: rgba(175, 47, 47, 0.1); | |
| } | |
| .filters li a.selected { | |
| border-color: rgba(175, 47, 47, 0.2); | |
| } | |
| .clear-completed, | |
| html .clear-completed:active { | |
| float: right; | |
| position: relative; | |
| line-height: 20px; | |
| text-decoration: none; | |
| cursor: pointer; | |
| } | |
| .clear-completed:hover { | |
| text-decoration: underline; | |
| } | |
| .info { | |
| margin: 65px auto 0; | |
| color: #bfbfbf; | |
| font-size: 10px; | |
| text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); | |
| text-align: center; | |
| } | |
| .info p { | |
| line-height: 1; | |
| } | |
| .info a { | |
| color: inherit; | |
| text-decoration: none; | |
| font-weight: 400; | |
| } | |
| .info a:hover { | |
| text-decoration: underline; | |
| } | |
| /* | |
| Hack to remove background from Mobile Safari. | |
| Can't use it globally since it destroys checkboxes in Firefox | |
| */ | |
| @media screen and (-webkit-min-device-pixel-ratio:0) { | |
| .toggle-all, | |
| .todo-list li .toggle { | |
| background: none; | |
| } | |
| .todo-list li .toggle { | |
| height: 40px; | |
| } | |
| } | |
| @media (max-width: 430px) { | |
| .footer { | |
| height: 50px; | |
| } | |
| .filters { | |
| bottom: 10px; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "version": "0.15.0", | |
| "EmberENV": { | |
| "FEATURES": {} | |
| }, | |
| "options": { | |
| "use_pods": false, | |
| "enable-testing": false | |
| }, | |
| "dependencies": { | |
| "jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js", | |
| "ember": "3.2.2", | |
| "ember-template-compiler": "3.2.2", | |
| "ember-testing": "3.2.2" | |
| }, | |
| "addons": { | |
| "ember-redux": "4.0.0", | |
| "ember-reselect-shim": "2.0.0", | |
| "ember-lodash-es-shim": "1.1.0" | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment