gun/examples/vue/todo.html
2017-10-24 00:32:31 -07:00

164 lines
4.0 KiB
HTML

<!doctype html>
<html>
<head>
<title>Todo App: Gun + Vue</title>
<script src="https://unpkg.com/vue" type="text/javascript" charset="utf-8"></script>
<script src="https://cdn.jsdelivr.net/npm/gun/gun.js" type="text/javascript" charset="utf-8"></script>
<link href='https://fonts.googleapis.com/css?family=Alegreya+Sans:300italic' rel='stylesheet' type='text/css'>
<style>
body,
html {
width: 100%;
font-family: 'Alegreya Sans', sans-serif;
}
body {
font-size: 20px;
background-color: rgba(0,0,0,.3);
}
h1,
h3,
h5 {
text-transform: uppercase;
font-weight: 600;
}
#app {
margin: 0 auto;
background-color: #fff;
max-width: 500px;
padding: 2em;
}
.add-todo {
font-size: 1em;
border: 1px solid black;
padding: .5em .25em;
}
.completed-header,
.completed,
.completed-time {
color: rgba(0,0,0,.3);
}
.completed {
text-decoration: line-through;
}
.completed-time {
font-size: .8em;
}
</style>
</head>
<body>
<div id="app">
<div class="todo-wrapper">
<h1>Todos App</h1>
<input class="add-todo" type="text" placeholder="Add new todo" v-model="newTodo" @keyup.enter="addTodo">
<h3>Active</h3>
<div v-for="active in activeTodos">
<label><input type="checkbox" @click.prevent="completeTodo(active.key)"> {{ active.todo.description }}</label>
</div>
<h5 v-show="completedTodos.length > 0" class="completed-header">Completed</h5>
<div v-for="completed in completedTodos" @click="reopenTodo(completed.key)">
<span class="completed">{{ completed.todo.description }}</span>
<span class="completed-time">(completed at {{ (new Date(completed.todo.completed)).toUTCString() }})</span>
</div>
</div>
</div>
</body>
<script>
// Clear out local storage so we can start fresh each time.
localStorage.clear();
// No peers for the sake of example,
// but this could easily be a collaborative
// todolist by adding a few peers
var gun = new Gun();
var todos = gun.get('todos');
new Vue({
data: {
todos: [],
newTodo: ""
},
computed: {
activeTodos: function() {
return this.todos.filter(function(todo) {
return todo.todo.completed === '';
});
},
completedTodos: function() {
return this.todos.filter(function(todo) {
return todo.todo.completed !== '';
});
}
},
methods: {
todoUpdated: function(todo, nodeKey) {
if (/\D/.test(nodeKey)) {
return;
}
var existingTodoIndex = this.todos.findIndex(function(todo) {
return todo.key === nodeKey
});
var todoToStore = {
todo: todo,
key: nodeKey
};
if (existingTodoIndex === -1) {
this.todos.push(todoToStore);
} else {
this.todos.splice(existingTodoIndex, 1, todoToStore);
}
},
addTodo: function() {
var newTodo = todos.get(Date.now().toString());
newTodo.put({
description: this.newTodo,
completed: ''
});
todos.set(newTodo);
this.newTodo = "";
},
completeTodo: function(key) {
todos.get(key).put({
completed: Date.now()
});
},
reopenTodo: function(key) {
todos.get(key).put({
completed: ''
});
}
},
mounted: function() {
// Subscribe to updates on the todos set
todos.map().on(this.todoUpdated.bind(this));
}
}).$mount('#app');
</script>
</html>