From b05feb5bf76922d1777ec2f6c97159069d2e3df1 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 8 Jun 2018 08:38:32 +0900
Subject: [PATCH] =?UTF-8?q?MisskeyDeck:=20=E3=83=89=E3=83=A9=E3=83=83?=
 =?UTF-8?q?=E3=82=B0=E3=81=A7=E3=82=AB=E3=83=A9=E3=83=A0=E3=82=92=E5=85=A5?=
 =?UTF-8?q?=E3=82=8C=E6=9B=BF=E3=81=88=E3=82=89=E3=82=8C=E3=82=8B=E3=82=88?=
 =?UTF-8?q?=E3=81=86=E3=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../desktop/views/pages/deck/deck.column.vue  | 67 ++++++++++++++++++-
 src/client/app/store.ts                       | 16 +++++
 2 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/src/client/app/desktop/views/pages/deck/deck.column.vue b/src/client/app/desktop/views/pages/deck/deck.column.vue
index 3e26d8630..7c97e4506 100644
--- a/src/client/app/desktop/views/pages/deck/deck.column.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.column.vue
@@ -1,6 +1,15 @@
 <template>
-<div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs" :class="{ naked, narrow, active, isStacked }">
-	<header :class="{ indicate: count > 0 }" @click="toggleActive">
+<div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs" :class="{ naked, narrow, active, isStacked, draghover, dragging }">
+	<header :class="{ indicate: count > 0 }"
+			draggable="true"
+			@click="toggleActive"
+			@dragstart="onDragstart"
+			@dragend="onDragend"
+			@dragover.prevent.stop="onDragover"
+			@dragenter.prevent="onDragenter"
+			@dragleave="onDragleave"
+			@drop.prevent.stop="onDrop"
+		>
 		<slot name="header"></slot>
 		<span class="count" v-if="count > 0">({{ count }})</span>
 		<button ref="menu" @click.stop="showMenu">%fa:caret-down%</button>
@@ -53,7 +62,9 @@ export default Vue.extend({
 	data() {
 		return {
 			count: 0,
-			active: true
+			active: true,
+			dragging: false,
+			draghover: false
 		};
 	},
 
@@ -162,6 +173,49 @@ export default Vue.extend({
 				compact: false,
 				items
 			});
+		},
+
+		onDragstart(e) {
+			e.dataTransfer.effectAllowed = 'move';
+			e.dataTransfer.setData('mk-deck-column', this.column.id);
+			this.dragging = true;
+		},
+
+		onDragend(e) {
+			this.dragging = false;
+		},
+
+		onDragover(e) {
+			// 自分自身がドラッグされている場合
+			if (this.dragging) {
+				// 自分自身にはドロップさせない
+				e.dataTransfer.dropEffect = 'none';
+				return;
+			}
+
+			const isDeckColumn = e.dataTransfer.types[0] == 'mk-deck-column';
+
+			e.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none';
+		},
+
+		onDragenter() {
+			if (!this.dragging) this.draghover = true;
+		},
+
+		onDragleave() {
+			this.draghover = false;
+		},
+
+		onDrop(e) {
+			this.draghover = false;
+
+			const id = e.dataTransfer.getData('mk-deck-column');
+			if (id != null && id != '') {
+				this.$store.dispatch('settings/swapDeckColumn', {
+					a: this.column.id,
+					b: id
+				});
+			}
 		}
 	}
 });
@@ -181,6 +235,10 @@ root(isDark)
 	box-shadow 0 2px 16px rgba(#000, 0.1)
 	overflow hidden
 
+	&.draghover
+	&.dragging
+		box-shadow 0 0 0 2px rgba($theme-color, 0.7)
+
 	&:not(.active)
 		flex-basis $header-height
 		min-height $header-height
@@ -213,6 +271,9 @@ root(isDark)
 		&, *
 			user-select none
 
+		*:not(button)
+			pointer-events none
+
 		&.indicate
 			box-shadow 0 3px 0 0 $theme-color
 
diff --git a/src/client/app/store.ts b/src/client/app/store.ts
index e6c3863d7..0dbdf9bd5 100644
--- a/src/client/app/store.ts
+++ b/src/client/app/store.ts
@@ -182,6 +182,17 @@ export default (os: MiOS) => new Vuex.Store({
 					state.deck.layout = state.deck.layout.map(ids => ids.filter(x => x != id));
 				},
 
+				swapDeckColumn(state, x) {
+					const a = x.a;
+					const b = x.b;
+					const aX = state.deck.layout.findIndex(ids => ids.indexOf(a) != -1);
+					const aY = state.deck.layout[aX].findIndex(id => id == a);
+					const bX = state.deck.layout.findIndex(ids => ids.indexOf(b) != -1);
+					const bY = state.deck.layout[bX].findIndex(id => id == b);
+					state.deck.layout[aX][aY] = b;
+					state.deck.layout[bX][bY] = a;
+				},
+
 				swapLeftDeckColumn(state, id) {
 					state.deck.layout.some((ids, i) => {
 						if (ids.indexOf(id) != -1) {
@@ -306,6 +317,11 @@ export default (os: MiOS) => new Vuex.Store({
 					ctx.dispatch('saveDeck');
 				},
 
+				swapDeckColumn(ctx, id) {
+					ctx.commit('swapDeckColumn', id);
+					ctx.dispatch('saveDeck');
+				},
+
 				swapLeftDeckColumn(ctx, id) {
 					ctx.commit('swapLeftDeckColumn', id);
 					ctx.dispatch('saveDeck');