<h1>Task Manager</h1>

<div id="app">
  <div class="column status__1">
    <p class="tag tag1">
      まだ
      <span>{{ tasksOpen.length }}</span>
    </p>
    <transition-group name="fade">
      <task-card :task="task" v-for="task in tasksOpen" :key="task.name"></task-card>
    </transition-group>
  </div>
  <div class="column status__2">
    <p class="tag tag2">
      やってる
      <span>{{ tasksDoing.length }}</span>
    </p>
    <transition-group name="fade">
      <task-card :task="task" v-for="task in tasksDoing" :key="task.name"></task-card>
    </transition-group>
  </div>
  <div class="column status__3">
    <p class="tag tag3">
      おわり
      <span>{{ tasksClosed.length }}</span>
    </p>
    <transition-group name="fade">
      <task-card :task="task" v-for="task in tasksClosed" :key="task.name"></task-card>
    </transition-group>
  </div>
  <div class="newTaskArea">
    <input type="text" v-model="newTaskName" placeholder="やること">
    <select v-model="newTaskAsignee">
      <option disabled>やらせる人を選択</option>
      <option value="🐶">🐶</option>
      <option value="🐱">🐱</option>
      <option value="🐵">🐵</option>
      <option value="🐧">🐧</option>
    </select>
    <input type="number" v-model="newTaskMandays" placeholder="人/日">
    <button @click="addTask">新規追加</button>
  </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue"></script>

$fa: "Font Awesome 5 Free"

*, *::before, *::after
  padding: 0
  margin: 0
  box-sizing: border-box

body
  background: whitesmoke
  color: #333
  padding: 10px
  
h1
  text-align: center
  margin-bottom: 1em

#app
  display: flex
  flex-wrap: wrap
  width: 100%
  max-width: 900px
  margin: 0 auto
  .status
    &__1
      border-top: 5px solid lightpink
    &__2
      border-top: 5px solid lightskyblue
    &__3
      border-top: 5px solid lightseagreen
  .column
    width: 300px
    padding: 10px
    margin: 0 auto
    background: white
    p.tag
      font-size: 15px
      line-height: 20px
      text-align: center 
      margin-bottom: 30px
      &::before
        font-family: $fa
        font-weight: 900
        margin-right: .5em
      &1::before
        content: '\f024'
        color: lightpink
      &2::before
        content: '\f303'
        color: lightskyblue
      &3::before
        content: '\f00c'
        color: lightseagreen
      & > span
        display: inline-block
        width: 20px
        min-width: 20px
        line-height: 20px
        background: #ccc
        border-radius: 50%
        color: white
        text-align: center
        vertical-align: middle
        margin-left: 1em
    .card
      width: 100%
      padding: 10px
      overflow: hidden
      position: relative
      border-radius: 3px
      box-shadow: 0 0 3px rgba(0,0,0,.2)
      margin-bottom: 10px
      p
        padding: 15px
      &__bg
        position: absolute
        font-size: 3em
        top: -20px
        left: -10px
        opacity: .2
      &__footer
        display: flex
        justify-content: space-between
        span
          color: #ccc
          transition: all .2s
          &:hover
            color: #333      
  .fade-enter-active, .fade-leave-active
    transition: opacity .7s
  .fade-enter, .fade-leave-to
    opacity: 0
  .newTaskArea
    margin-top: 15px
    padding: 20px 10px
    background: white
    width: 100%
    display: flex
    flex-wrap: wrap
    justify-content: space-between
    input, select, button
      min-width: 180px
      margin: 10px 20px
      padding: 5px
      border-radius: 3px
    button
      flex-grow: 2
View Compiled
Vue.component('task-card', {
  props: ['task'],
  template: '<div class="card"><p>{{ task.name }}</p><div class="card__bg">{{ task.asignee }}</div><div class="card__footer"><span @click="decStatus(task)"><i class="fas fa-chevron-circle-left"></i></span><span>{{ task.mandays }}人/日</span><span @click="incStatus(task)"><i class="fas fa-chevron-circle-right"></i></span></div></div>',
  methods: {
    incStatus(task){
      if(1 <= task.status && task.status <= 2){
        task.status ++
      }
    },
    decStatus(task){
      if(2 <= task.status && task.status <= 3){
        task.status --
      }
    }
  }
})

let filters = {
  open: function(tasks){
    return tasks.filter(function(task){
      return task.status === 1           
    })
  },
  doing: function(tasks){
    return tasks.filter(function(task){
      return task.status === 2
    })
  },
  closed: function(tasks){
    return tasks.filter(function(task){
      return task.status === 3
    })
  }
}

let vm = new Vue({
  el: '#app',
  data: {
    tasks: [
      { name: 'task1', status : 1, asignee: '🐶', mandays : 3 },
      { name: 'task2', status : 2, asignee: '🐱', mandays : 3 },
      { name: 'task3', status : 1, asignee: '🐵', mandays : 1 },
      { name: 'task4', status : 3, asignee: '🐧', mandays : 2 }
    ],
    newTaskName: '',
    newTaskAsignee: null,
    newTaskMandays: 0
  },
  computed: {
    tasksOpen: function(){
      return filters.open(this.tasks)
    },
    tasksDoing: function(){
      return filters.doing(this.tasks)
    },
    tasksClosed: function(){
      return filters.closed(this.tasks)
    }
  },
  methods: {
    addTask(){
      this.tasks.push({ name: this.newTaskName, status: 1, asignee: this.newTaskAsignee, mandays: this.newTaskMandays })
    }
  }
})
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.