tnerbovik
6/21/2017 - 11:15 AM

KanbanView.vue

<template>
  <section class="component">
    <div class="wrapper">
      <draggable element="ul" :list="cards" class="boards" :move="checkMove">
        <li class="board" v-for="card in cards">
          <div class="card">
            <div class="card__header">
              <h4>{{ card.name }}</h4>
            </div>
            <div class="card__body">
              <local-draggable v-if="card.tasks" :tasks="card.tasks"></local-draggable>
            </div>
          </div>
        </li>
      </draggable>
    </div>
  </section>
</template>

<script>
import draggable from 'vuedraggable'
import localDraggable from 'components/kanban/localDraggable.vue'

export default {
  name: 'ProjectKanban',
  components: {
    draggable,
    localDraggable
  },
  data() {
    return {
      "cards": [
        {
          "name": "Backlog",
          "tasks": [
            {
              "name": "Task 1",
            },
            {
              "name": "Task 2",
            },
            {
              "name": "Task 3",
            }
          ]
        },
        {
          "name": "Card 2",
          "tasks": [
            {
              "name": "Task 4"
            },
            {
              "name": "Task 5"
            }
          ]
        }
      ]
    }
  },
  methods: {
    checkMove(evt) {
      console.log('Card moved');
    }
  },
  beforeRouteEnter(to, from, next) {
    const fetchers = []
    Promise.all(fetchers).then(() => {
      next()
    })
  }
}
</script>

<style lang="scss" >
.boards {
  display: flex;
}

.card {
  background: lighten(#c3cfe2, 10);
}

.card__header {
  border: none;
  padding: .5rem .75rem;
}

.card__header div {
  display: flex;
  border: none;
  justify-content: space-between!important;
}

.card__header div h4 {
  flex: 1;
  border: none;
  font-weight: 700;
  font-size: .9rem;
}

.card__body {
  padding: .5rem .75rem;

  li {}
}

.board {

  margin: 1rem;
  height: 100%;
  flex: 1;
  width: 250px;
  max-width: 280px;
  border: 1px solid transparent;
  border-radius: 3px;
  &.sortable-ghost {
    opacity: 1;
    background: darken(#c3cfe2, 5);
    border-bottom: 1px solid lighten(#c3cfe2, 5);
    border-right: 1px solid lighten(#c3cfe2, 5);
    border-top: 1px solid darken(#c3cfe2, 10);
    border-left: 1px solid darken(#c3cfe2, 10);
    min-height: 300px;
  }
  &.sortable-ghost>* {
    display: none;
  }
}

.sortable-drag>div {
  -webkit-transform: rotate(3deg);
  opacity: 1;
}

.task>div {
  border-radius: 3px;

  padding: .5rem .5rem;
  background: white;
  font-size: .85rem;
  font-weight: 400;

  border-top: 1px solid lighten(#c3cfe2, 18);
  border-left: 1px solid lighten(#c3cfe2, 18);
  border-right: 1px solid lighten(#c3cfe2, 5);
  border-bottom: 1px solid lighten(#c3cfe2, 5);
  margin-bottom: .5rem!important;
}

.sortable-drag {
  cursor: -webkit-grab!important;
  cursor: grab!important;
}

.task {

  margin-bottom: .5rem;
  &.sortable-chosen {
    opacity: 1;
  }

  &.sortable-ghost {
    opacity: 1;
    background: #c3cfe2;
    border-bottom: 1px solid lighten(#c3cfe2, 18);
    border-right: 1px solid lighten(#c3cfe2, 18);
    border-top: 1px solid lighten(#c3cfe2, 5);
    border-left: 1px solid lighten(#c3cfe2, 5);
    min-height: 42px;
  }
  &.sortable-ghost>* {
    display: none;
  }
}
</style>