Created
September 9, 2018 04:07
-
-
Save tak1827/9a901a30fc7dfa7e39c068fc19efc2a4 to your computer and use it in GitHub Desktop.
Todo app hosted by IPFS. Access https://ipfs.io/ipfs/QmduLe5ZEcNUA6F8x3nwg6qpuy6DJfg3kW7APfGx17eVmi
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
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0"> | |
<title>IPFS TodoApp</title> | |
<!-- CSS --> | |
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> | |
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css"> | |
</head> | |
<body> | |
<!-- Todo Container --> | |
<div class="container"> | |
<div class="card"> | |
<div class="card-image"> | |
<img src="https://ipfs.io/ipfs/QmahhVnsP7eRA5MTrE3fQeV8eY8aKmCuUydXP6LuFjLqfs"> | |
<span class="card-title">Todo App hosted by IPFS</span> | |
</div> | |
<!-- Card Content --> | |
<div class="card-content"> | |
<form class="col s12"> | |
<p>Please input your todo</p> | |
<div class="row"> | |
<div class="input-field col s11"> | |
<input id="new-todo" type="text"> | |
</div> | |
<div class="col s1"> | |
<a id="add-btn" class="btn-floating btn-large waves-effect waves-light"><i class="material-icons">add</i></a> | |
</div> | |
</div> | |
</form> | |
<ul id="todo-list" class="collection with-header"> | |
<!-- <li class="collection-item"> | |
<input type="checkbox" id="todo0"> | |
<label for="todo0">Buy Materialize Admin Theme.</label> | |
</li> --> | |
</ul> | |
<div> | |
<input type="radio" name="visibility" id="show-all" value="all" checked/> | |
<label id="show-all-label" for="show-all" style="margin-right:32px">Show All</label> | |
<input type="radio" name="visibility" id="show-active" value="active"/> | |
<label id="show-active-label" for="show-active" style="margin-right:32px">Show Active</label> | |
<input type="radio" name="visibility" id="show-completed" value="completed"/> | |
<label id="show-completed-label" for="show-completed" style="margin-right:32px">Show Completed</label> | |
</div> | |
</div> | |
<!-- Card Content --> | |
</div> | |
</div> | |
<!-- Todo Container --> | |
</body> | |
<script> | |
/*************************** | |
Redux CreateStore | |
***************************/ | |
const createStore = reducer => { | |
let state; | |
const subscribers = []; | |
const store = { | |
dispatch: action => { | |
state = reducer(state, action); | |
subscribers.forEach(handler => handler()); | |
}, | |
getState: () => state, | |
subscribe: handler => { | |
subscribers.push(handler); | |
} | |
}; | |
return store; | |
} | |
/*************************** | |
Redux CombineReducers | |
***************************/ | |
const combineReducers = (reducers) => { | |
return (state = {}, action) => { | |
return Object.keys(reducers).reduce( | |
(nextState, key) => { | |
nextState[key] = reducers[key] ( | |
state[key], | |
action | |
) | |
return nextState; | |
}, | |
{} | |
) | |
} | |
} | |
/*************************** | |
Define reducers | |
***************************/ | |
const CREATE_NOTE = 'CREATE_NOTE'; | |
const TOGGLE_TODO = 'TOGGLE_TODO'; | |
// Todo reducer | |
const todosReducer = (state = [], action) => { | |
switch (action.type) { | |
case CREATE_NOTE: | |
return [ | |
...state, | |
{ | |
id: state.length, | |
content: action.txt, | |
completed: false | |
} | |
] | |
case TOGGLE_TODO: | |
return state.map(todo => | |
(todo.id === action.id) | |
? {...todo, completed: !todo.completed } | |
: todo | |
) | |
default: | |
return state; | |
} | |
} | |
const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER'; | |
const vFilters = { SHOW_ALL: 'SHOW_ALL', SHOW_ACTIVE: 'SHOW_ACTIVE', SHOW_COMPLETED: 'SHOW_COMPLETED' } | |
// Visibility filter reducer | |
const visibilityReducer = (state = vFilters.SHOW_ALL, action) => { | |
switch (action.type) { | |
case 'SET_VISIBILITY_FILTER': | |
return action.filter | |
default: | |
return state | |
} | |
} | |
/*************************** | |
Create todo app | |
***************************/ | |
const todoApp = combineReducers({ | |
todosReducer, | |
visibilityReducer | |
}); | |
const store = createStore(todoApp); | |
// Subscribe state change | |
store.subscribe(() => { | |
const state = store.getState(); | |
console.log(state); | |
createTodoList( getVisibleTodos(state.todosReducer, state.visibilityReducer) ); | |
}); | |
const createTodoList = (todos) => { | |
const ul = document.getElementById("todo-list"); | |
// Delete all todos | |
while (ul.firstChild) ul.removeChild(ul.firstChild); | |
// Creare todos | |
todos.forEach(todo => { | |
// Create elements | |
let li = document.createElement("li"); | |
let input = document.createElement("input"); | |
let label = document.createElement("label"); | |
li.appendChild(input); | |
li.appendChild(label); | |
ul.appendChild(li); | |
// Set attributes | |
input.setAttribute("type", "checkbox"); | |
input.setAttribute("id", "todo"+todo.id); | |
label.setAttribute("for", "todo"+todo.id); | |
li.className = 'collection-item'; | |
label.innerHTML = todo.content; | |
if (todo.completed) input.checked = true; | |
// Dispatch toggle action when clicked | |
label.onclick = () => { | |
setTimeout(() => store.dispatch({type: TOGGLE_TODO, id: todo.id}), 1000); | |
}; | |
}); | |
} | |
const getVisibleTodos = (todos, filter) => { | |
switch (filter) { | |
case vFilters.SHOW_ALL: | |
return todos | |
case vFilters.SHOW_COMPLETED: | |
return todos.filter(t => t.completed) | |
case vFilters.SHOW_ACTIVE: | |
return todos.filter(t => !t.completed) | |
default: | |
throw new Error('Unknown filter: ' + filter) | |
} | |
} | |
/*************************** | |
Add event lisner | |
***************************/ | |
document.getElementById("add-btn").onclick = () => { | |
const txt = document.getElementById("new-todo").value | |
store.dispatch({type: CREATE_NOTE, txt}); | |
document.getElementById("new-todo").value = ""; | |
}; | |
document.getElementById("show-all-label").onclick = () => { | |
store.dispatch({type: SET_VISIBILITY_FILTER, filter: vFilters.SHOW_ALL}); | |
}; | |
document.getElementById("show-active-label").onclick = () => { | |
store.dispatch({type: SET_VISIBILITY_FILTER, filter: vFilters.SHOW_ACTIVE}); | |
}; | |
document.getElementById("show-completed-label").onclick = () => { | |
store.dispatch({type: SET_VISIBILITY_FILTER, filter: vFilters.SHOW_COMPLETED}); | |
}; | |
/*************************** | |
Initialize todo app | |
***************************/ | |
store.dispatch({type: CREATE_NOTE, txt: "Smaple text1"}); | |
store.dispatch({type: CREATE_NOTE, txt: "Smaple text2"}); | |
store.dispatch({type: TOGGLE_TODO, id: 0}); | |
</script> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment