Kanban Board
Kanban Board is a tool for managing tasks and workflow. It is a visual way to manage tasks and workflow.
App.vue
1<script>2import yorkie from '@yorkie-js/sdk';34const initialRoot = {5 lists: [6 {7 title: 'Todo',8 cards: [{ title: 'Pruning document' }, { title: 'Clean up codes' }],9 },10 {11 title: 'Doing',12 cards: [{ title: 'Array operations' }],13 },14 {15 title: 'Done',16 cards: [{ title: 'Create a sample page' }, { title: 'Launch demo site' }],17 },18 ],19};2021const client = new yorkie.Client({22 rpcAddr: import.meta.env.VITE_YORKIE_API_ADDR,23 apiKey: import.meta.env.VITE_YORKIE_API_KEY,24});2526const doc = new yorkie.Document(27 `vuejs-kanban-${new Date().toISOString().substring(0, 10).replace(/-/g, '')}`,28 { enableDevtools: true },29);3031export default {32 data() {33 return {34 lists: [],35 title: '',36 opened: null,37 };38 },39 created() {40 this.fetchDoc();41 },42 watch: {43 opened(index) {44 this.$nextTick(function () {45 if (index === 0) {46 // Open add list form47 this.$refs['addListForm'].querySelector('input').focus();48 } else if (index) {49 // Or open add card form50 this.$refs['addCardForm'][index - 1].querySelector('input').focus();51 }52 this.title = '';53 });54 },55 },56 methods: {57 async fetchDoc() {58 await client.activate();59 await client.attach(doc, { initialRoot });6061 doc.subscribe((event) => {62 this.lists = doc.getRoot().lists;63 });64 await client.sync();6566 this.lists = doc.getRoot().lists;67 },6869 isOpened(index) {70 return this.opened === index;71 },7273 openForm(index) {74 this.opened = index;75 },7677 closeForm() {78 this.opened = null;79 },8081 addCard(list) {82 if (this.title === '') return;8384 doc.update((root) => {85 root.lists.getElementByID(list.getID()).cards.push({86 title: this.title,87 });88 this.title = '';89 }, `add new card by ${client.getID()}`);90 },9192 deleteCard(list, card) {93 doc.update((root) => {94 root.lists.getElementByID(list.getID()).cards.deleteByID(card.getID());95 }, `delete a card by ${client.getID()}`);96 },9798 addList() {99 if (this.title === '') return;100101 doc.update((root) => {102 root.lists.push({103 title: this.title,104 cards: [],105 });106 this.title = '';107 }, `add new list by ${client.getID()}`);108 },109110 deleteList(list) {111 doc.update((root) => {112 root.lists.deleteByID(list.getID());113 }, `delete a list by ${client.getID()}`);114 },115 },116};117</script>118119<template>120 <div v-cloak class="list" v-for="(list, index) in lists">121 <span class="delete" v-on:click="deleteList(list)">❌</span>122 <div class="title">{{ list.title }}</div>123 <div class="card" v-for="card in list.cards">124 <span class="delete" v-on:click="deleteCard(list, card)">❌</span>125 {{ card.title }}126 </div>127 <div class="add-card" ref="addCardForm">128 <div v-if="isOpened(index + 1)" class="add-form">129 <input130 type="text"131 placeholder="Enter card title"132 v-model="title"133 v-on:keyup.enter="addCard(list)"134 v-on:keyup.esc="closeForm()"135 />136 <div class="buttons">137 <input type="button" value="Add" v-on:click="addCard(list)" />138 <input139 type="button"140 value="Close"141 class="pull-right"142 v-on:click="closeForm()"143 />144 </div>145 </div>146 <div v-else class="add-card-opener" v-on:click="openForm(index + 1)">147 Add another card148 </div>149 </div>150 </div>151 <div class="add-list" ref="addListForm">152 <div v-if="isOpened(0)" class="add-form">153 <input154 type="text"155 placeholder="Enter list title"156 v-model="title"157 v-on:keyup.enter="addList()"158 v-on:keyup.esc="closeForm()"159 />160 <div class="buttons">161 <input type="button" value="Add" v-on:click="addList()" />162 <input163 type="button"164 value="Close"165 class="pull-right"166 v-on:click="closeForm()"167 />168 </div>169 </div>170 <div v-else class="add-list-opener" v-on:click="openForm(0)">171 Add another list172 </div>173 </div>174</template>
export type KanbanDoc = {lists: Array<List>;};export type List = {title: string;cards: Array<Card>;};export type Card = {title: string;};
- User 1
- User 2
- User 1
- User 2