Skip to content
This repository was archived by the owner on Dec 2, 2024. It is now read-only.

Commit 1929bf5

Browse files
committed
feat: add drag and drop to the board
1 parent bd17951 commit 1929bf5

15 files changed

+510
-6294
lines changed

electron-vendors.config.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
22
"chrome": "91",
3-
"node": "14"
3+
"node": "16.4.0"
44
}

package.json

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
{
22
"name": "vite-electron-builder",
33
"private": true,
4-
"engines": {
5-
"node": ">=v14.16"
6-
},
74
"main": "packages/main/dist/index.cjs",
85
"scripts": {
96
"buildEnvTypes": "node scripts/buildEnvTypes.js",
@@ -14,7 +11,7 @@
1411
"test": "node tests/app.spec.js",
1512
"watch": "node scripts/watch.js",
1613
"lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
17-
"anu": "cd .\\node_modules\\node-pty && node-gyp rebuild --target=13.1.0 --arch=x64 --target_platform=darwin --dist-url=https://atom.io/download/atom-shell"
14+
"rebuild": "./node_modules/.bin/electron-rebuild.cmd"
1815
},
1916
"browserslist": [
2017
"Chrome 91"
@@ -24,10 +21,6 @@
2421
},
2522
"dependencies": {
2623
"@mdi/js": "^5.9.55",
27-
"@tiptap/extension-task-item": "^2.0.0-beta.16",
28-
"@tiptap/extension-task-list": "^2.0.0-beta.16",
29-
"@tiptap/starter-kit": "^2.0.0-beta.76",
30-
"@tiptap/vue-3": "^2.0.0-beta.40",
3124
"@vuex-orm/core": "^0.36.4",
3225
"@vuex-orm/plugin-search": "^0.23.4",
3326
"dayjs": "^1.10.5",
@@ -50,6 +43,7 @@
5043
"vue-mdijs": "^0.5.0",
5144
"vue-router": "^4.0.8",
5245
"vue-toastification": "^2.0.0-rc.1",
46+
"vuedraggable": "^4.0.3",
5347
"vuex": "^4.0.1",
5448
"xterm": "^4.13.0"
5549
},

packages/main/src/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ ipcMain.on('node-pty', (event, options = {}) => {
161161
if (options.write) ptyProcess.write(options.write);
162162

163163
ptyProcess.on('data', function(data) {
164-
ipcMain.send('pty-data', { name: options.name, data });
164+
mainWindow.webContents.send('pty-data', { name: options.name, data });
165165
});
166166

167167
allPtyProcess[options.name] = ptyProcess;

packages/renderer/src/components/boards/AddCard.vue

+7
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,17 @@ export default {
104104
card.data.tasks.splice(index, 1);
105105
}
106106
function saveCard() {
107+
let maxOrder = Card.query().where('boardId', props.boardId).max('order');
108+
109+
if (card.id) {
110+
maxOrder = card.order;
111+
}
112+
107113
Card.insertOrUpdate({
108114
data: {
109115
...card,
110116
type: 'card',
117+
order: card.id ? maxOrder : maxOrder + 1,
111118
id: card.id ? card.id : nanoid(),
112119
boardId: props.boardId,
113120
},

packages/renderer/src/components/boards/AddIssueCard.vue

+4
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,11 @@ export default {
116116
function addCard() {
117117
if (!props.boardId || state.selectedIssues.length === 0) return;
118118
119+
let maxOrder =
120+
(Card.query().where('boardId', props.boardId).max('order') || 0) - 1;
121+
119122
const data = state.selectedIssues.map((id) => ({
123+
order: (maxOrder += 1),
120124
type: 'issue',
121125
boardId: props.boardId,
122126
data: issues.value.find((issue) => issue.id === id) || {},

packages/renderer/src/components/boards/BoardCard.vue

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
<template>
22
<ui-card class="group">
33
<div class="flex items-center">
4-
<p
5-
class="text-overflow font-semibold flex-1 cursor-pointer pr-2"
6-
@click="editCard"
7-
>
4+
<p class="text-overflow flex-1 cursor-pointer pr-2" @click="editCard">
85
{{ card.name }}
96
</p>
107
<ui-popover>

packages/renderer/src/components/boards/BoardColumn.vue

+46-10
Original file line numberDiff line numberDiff line change
@@ -55,28 +55,35 @@
5555
</ui-list>
5656
</ui-popover>
5757
</div>
58-
<div class="space-y-2 overflow-auto flex-1 scroll pb-4">
59-
<transition-group-list>
58+
<draggable
59+
v-model="cards"
60+
:animation="500"
61+
item-key="id"
62+
group="cards"
63+
class="space-y-2 overflow-auto flex-1 scroll"
64+
@change="onDragChange"
65+
>
66+
<template #item="{ element }">
6067
<component
61-
v-bind="{ key: card.id, card }"
62-
v-for="card in board.cards"
63-
:is="card.type === 'issue' ? 'board-issue-card' : 'board-card'"
64-
:key="card.id"
65-
class="transition-list"
68+
v-bind="{ card: element }"
69+
:is="element.type === 'issue' ? 'board-issue-card' : 'board-card'"
6670
@edit="$emit('modal', { ...$event, id: board.id })"
6771
></component>
68-
</transition-group-list>
69-
</div>
72+
</template>
73+
</draggable>
7074
</div>
7175
</template>
7276
<script>
77+
import { computed } from 'vue';
78+
import Draggable from 'vuedraggable/src/vuedraggable';
7379
import { useDialog } from '@/composable/dialog';
7480
import Board from '@/models/board';
81+
import Card from '@/models/card';
7582
import BoardCard from './BoardCard.vue';
7683
import BoardIssueCard from './BoardIssueCard.vue';
7784
7885
export default {
79-
components: { BoardCard, BoardIssueCard },
86+
components: { BoardCard, BoardIssueCard, Draggable },
8087
props: {
8188
board: {
8289
type: Object,
@@ -91,6 +98,22 @@ export default {
9198
setup(props) {
9299
const dialog = useDialog();
93100
101+
const cards = computed({
102+
get() {
103+
return Card.query()
104+
.where('boardId', props.board.id)
105+
.orderBy('order')
106+
.get();
107+
},
108+
set(value) {
109+
const data = value.map((item, index) => ({ ...item, order: index }));
110+
console.log(data);
111+
Card.update({
112+
data,
113+
});
114+
},
115+
});
116+
94117
function editBoard() {
95118
dialog.prompt({
96119
title: 'Edit board',
@@ -116,10 +139,23 @@ export default {
116139
Board.delete(props.board.id);
117140
}
118141
}
142+
function onDragChange(event) {
143+
if (event.added) {
144+
Card.update({
145+
where: event.added.element.id,
146+
data: {
147+
order: event.added.newIndex,
148+
boardId: props.board.id,
149+
},
150+
});
151+
}
152+
}
119153
120154
return {
155+
cards,
121156
editBoard,
122157
deleteBoard,
158+
onDragChange,
123159
};
124160
},
125161
};

packages/renderer/src/components/package/PackageDetails.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
</div>
8181
<ui-tabs
8282
v-model="state.activeTab"
83-
class="bg-gray-800 z-50 sticky top-0"
83+
class="bg-gray-800 z-50 sticky top-0 mb-4"
8484
>
8585
<ui-tab
8686
v-for="tab in tabs"

packages/renderer/src/components/ui/Checkbox.vue

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
text-primary
88
shadow-sm
99
cursor-pointer
10-
focus:border-primary
11-
focus:ring focus:ring-primary
10+
focus:border-primary focus:ring focus:ring-primary
1211
transition
1312
h-4
1413
w-4

packages/renderer/src/models/board.js

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class Board extends Model {
1313
name: this.string(''),
1414
projectId: this.attr(null),
1515
cards: this.hasMany(Card, 'boardId'),
16+
order: this.number(0),
1617
createdAt: this.number(Date.now()),
1718
};
1819
}

packages/renderer/src/models/card.js

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class Card extends Model {
1212
name: this.string(''),
1313
type: this.string(''),
1414
data: this.attr(null),
15+
order: this.number(0),
1516
boardId: this.attr(null),
1617
description: this.string(''),
1718
};

packages/renderer/src/pages/project/[id].vue

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<template>
22
<div class="px-5 pt-5 h-full">
3-
<router-view v-bind="{ project, packageJSON }"></router-view>
3+
<router-view v-slot="{ Component }">
4+
<keep-alive include="MoviesList">
5+
<component :is="Component" v-bind="{ project, packageJSON }" />
6+
</keep-alive>
7+
</router-view>
48
</div>
59
</template>
610
<script>

packages/renderer/src/pages/project/[id]/boards.vue

+31-14
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,22 @@
1111
<p v-if="boards.length === 0" class="text-center text-gray-200">
1212
You have no boards
1313
</p>
14-
<template v-else>
15-
<div
16-
class="flex space-x-6 scroll pb-4 overflow-auto"
17-
style="height: calc(100vh - 6.5rem)"
18-
>
14+
<draggable
15+
v-else
16+
v-model="boards"
17+
:animation="250"
18+
item-key="id"
19+
group="boards"
20+
class="flex space-x-6 scroll pb-4 overflow-auto"
21+
style="height: calc(100vh - 6.5rem)"
22+
>
23+
<template #item="{ element }">
1924
<board-column
20-
v-for="board in boards"
21-
v-bind="{ key: board.id, board, repository: project.repository }"
22-
:key="board.id"
25+
v-bind="{ board: element, repository: project.repository }"
2326
@modal="showModal"
2427
></board-column>
25-
</div>
26-
</template>
28+
</template>
29+
</draggable>
2730
<ui-modal v-model="modalState.show" position="items-start">
2831
<template #header>
2932
<p>{{ modalState.type === 'issue' ? 'Add Issue Card' : 'Add Card' }}</p>
@@ -42,14 +45,15 @@
4245
import { computed, shallowReactive } from 'vue';
4346
import { useStore } from 'vuex';
4447
import { useRoute } from 'vue-router';
48+
import Draggable from 'vuedraggable/src/vuedraggable';
4549
import { useDialog } from '@/composable/dialog';
4650
import Board from '@/models/board';
4751
import AddCard from '@/components/boards/AddCard.vue';
4852
import BoardColumn from '@/components/boards/BoardColumn.vue';
4953
import AddIssueCard from '@/components/boards/AddIssueCard.vue';
5054
5155
export default {
52-
components: { AddCard, AddIssueCard, BoardColumn },
56+
components: { AddCard, AddIssueCard, BoardColumn, Draggable },
5357
props: {
5458
packageJSON: {
5559
type: Object,
@@ -72,18 +76,31 @@ export default {
7276
boardId: '',
7377
});
7478
75-
const boards = computed(() =>
76-
Board.query().where('projectId', route.params.id).with('cards').get()
77-
);
79+
const boards = computed({
80+
get() {
81+
return Board.query()
82+
.where('projectId', route.params.id)
83+
.orderBy('order')
84+
.get();
85+
},
86+
set(value) {
87+
const data = value.map((item, index) => ({ ...item, order: index }));
88+
89+
Board.update({ data });
90+
},
91+
});
7892
7993
function addBoard() {
8094
dialog.prompt({
8195
title: 'Add board',
8296
label: 'Board name',
8397
onConfirm(name) {
98+
const maxOrder = Board.query().max('order');
99+
84100
Board.insert({
85101
data: {
86102
name,
103+
order: maxOrder + 1,
87104
projectId: route.params.id,
88105
},
89106
});

0 commit comments

Comments
 (0)