Vue

by Alexandru Gatea

HTML

<div id="todo-list">
    <form class="add-todo card" v-on:submit.prevent="addNewTodo">
        <label for="new-todo">Add a todo</label>
        <input v-model="newTodoText" id="new-todo" placeholder="E.g. Feed the cat" autocomplete="off" autocorrect="off">
        <button>Add</button>
    </form>
    <ul class="todo-list">
        <li 
            class="card" 
            is="todo-item" 
            v-for="todo in todos" 
            v-bind:title="todo.title"
            v-bind:url="todo.url"
            v-on:remove="todos.splice(index, 1)">
        </li>
    </ul>
</div>

SCSS

//fonts and variables

@import url('https://fonts.googleapis.com/css?family=Titillium+Web:300,400,700');

$font: 'Titillium Web', sans-serif;
$color: #ff3355;

* {
    box-sizing: border-box;
}


body {
    background: transparent;
    font-family: $font;
}

.card {
    background: #fff;
    display: block;
    padding: 20px;
    margin-bottom: 5px;
    border-radius: 5px;
}

.add-todo {
    background: $color;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    text-align: center;
    margin-bottom: 20px;
    label {
        display: block;
        width: 100%;
        font-size: 2em;
        line-height: 1;
        text-transform: uppercase;
        font-weight: bold;
        color: #fff;
        margin-bottom: 15px;
        margin-top: 0;
    }
    input {
        min-height: 50px;
        border-radius: 50px;
        border: 5px solid #fff;
        min-width: 300px;
        padding: 0 75px 0 25px;
        outline: none;
    }
    button {
        width: 80px;
        height: 40px;
        margin-top: 30px;
        margin-left: -60px;
        line-height: 40px;
        border-radius: 40px;
        color: #fff;
        background: #20262e;
        border: none;
        outline: none;
        cursor: pointer;
        box-shadow: -2px -2px 0px 4px $color;
    }
}

.todo-list {
    display: block;
    max-width: 80%;
    margin: auto;
    li {
        position: relative;
        transition: all 0.3s ease;
        top:0;
        display: flex;
        align-items: center;
        min-height: 64px;
        padding-left: 60px;
        img {
            width: 40px;
            height: 40px;
            object-fit: cover;
            margin-left: -40px;
            margin-right: 20px;
        }
    }
    button {
        position: absolute;
        top:0;
        right: 0;
        padding: 20px;
        height: 100%;
        display: block;
        background: transparent;
        outline: none;
        border: none;
     ...

Vue

Vue.component('todo-item', {
  template: '\
    <li>\
    	<img src="https://picsum.photos/200/300/?random">\
      	{{ title }}\
      	<button v-on:click="$emit(\'remove\')">&times;</button>\
    </li>\
  ',
  props: ['title']
})

new Vue({
  el: '#todo-list',
  data: {
    todos: [
      {
      	title: 'Do the dishes'
      },
			{
				title: 'do this'
			},
			{
				title: 'that also'
			}
    ]
  },
  methods: {
    addNewTodo: function () {
      this.todos.push({
        id: this.nextTodoId++,
        title: this.newTodoText
      })
      this.newTodoText = ''
    }
  }
})