feat: 턴 선택기에서 '드래그' 선택 지원
This commit is contained in:
@@ -50,17 +50,29 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="commandTable">
|
<div class="commandTable">
|
||||||
<template
|
<DragSelect
|
||||||
v-for="(turnObj, turnIdx) in reservedCommandList.slice(
|
:style="rowGridStyle"
|
||||||
0,
|
attribute="turnIdx"
|
||||||
Math.min(maxTurn, viewMaxTurn)
|
@dragStart="isDragToggle = true"
|
||||||
)"
|
@dragDone="
|
||||||
:key="turnIdx"
|
isDragToggle = false;
|
||||||
|
toggleTurn(...$event);
|
||||||
|
"
|
||||||
|
v-slot="{ selected }"
|
||||||
>
|
>
|
||||||
<div class="idx_pad center d-grid" @click="toggleTurn(turnIdx)">
|
<div
|
||||||
|
v-for="(turnObj, turnIdx) in reservedCommandList.slice(
|
||||||
|
0,
|
||||||
|
viewMaxTurn
|
||||||
|
)"
|
||||||
|
:turnIdx="turnIdx"
|
||||||
|
:key="turnIdx"
|
||||||
|
class="idx_pad center d-grid"
|
||||||
|
>
|
||||||
<b-button
|
<b-button
|
||||||
size="sm"
|
size="sm"
|
||||||
:variant="
|
:variant="
|
||||||
|
(isDragToggle && selected.has(`${turnIdx}`))?'light':
|
||||||
turnList.has(turnIdx)
|
turnList.has(turnIdx)
|
||||||
? 'info'
|
? 'info'
|
||||||
: turnList.size == 0 && prevTurnList.has(turnIdx)
|
: turnList.size == 0 && prevTurnList.has(turnIdx)
|
||||||
@@ -70,10 +82,26 @@
|
|||||||
>{{ turnIdx + 1 }}</b-button
|
>{{ turnIdx + 1 }}</b-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
</DragSelect>
|
||||||
|
<DragSelect
|
||||||
|
:style="rowGridStyle"
|
||||||
|
attribute="turnIdx"
|
||||||
|
@dragStart="isDragSingle = true"
|
||||||
|
@dragDone="
|
||||||
|
isDragSingle = false;
|
||||||
|
selectTurn(...$event);
|
||||||
|
"
|
||||||
|
v-slot="{ selected }"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
@click="selectTurn(turnIdx)"
|
v-for="(turnObj, turnIdx) in reservedCommandList.slice(
|
||||||
|
0,
|
||||||
|
viewMaxTurn
|
||||||
|
)"
|
||||||
|
:key="turnIdx"
|
||||||
height="24"
|
height="24"
|
||||||
class="month_pad center"
|
class="month_pad center"
|
||||||
|
:turnIdx="turnIdx"
|
||||||
:style="{
|
:style="{
|
||||||
'white-space': 'nowrap',
|
'white-space': 'nowrap',
|
||||||
'font-size': `${Math.min(
|
'font-size': `${Math.min(
|
||||||
@@ -81,18 +109,40 @@
|
|||||||
(75 / (`${turnObj.year ?? 1}`.length + 8)) * 1.8
|
(75 / (`${turnObj.year ?? 1}`.length + 8)) * 1.8
|
||||||
)}px`,
|
)}px`,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
|
color:
|
||||||
|
isDragSingle && selected.has(`${turnIdx}`) ? 'cyan' : undefined,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
{{ turnObj.year ? `${turnObj.year}年` : "" }}
|
{{ turnObj.year ? `${turnObj.year}年` : "" }}
|
||||||
{{ turnObj.month ? `${turnObj.month}月` : "" }}
|
{{ turnObj.month ? `${turnObj.month}月` : "" }}
|
||||||
</div>
|
</div>
|
||||||
|
</DragSelect>
|
||||||
|
<div :style="rowGridStyle">
|
||||||
<div
|
<div
|
||||||
|
v-for="(turnObj, turnIdx) in reservedCommandList.slice(
|
||||||
|
0,
|
||||||
|
viewMaxTurn
|
||||||
|
)"
|
||||||
|
:key="turnIdx"
|
||||||
class="time_pad center"
|
class="time_pad center"
|
||||||
style="background-color: black; white-space: nowrap; overflow: hidden"
|
:style="{
|
||||||
|
backgroundColor: 'black',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
overflow: 'hidden',
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
{{ turnObj.time }}
|
{{ turnObj.time }}
|
||||||
</div>
|
</div>
|
||||||
<div class="turn_pad center">
|
</div>
|
||||||
|
<div :style="rowGridStyle">
|
||||||
|
<div
|
||||||
|
v-for="(turnObj, turnIdx) in reservedCommandList.slice(
|
||||||
|
0,
|
||||||
|
viewMaxTurn
|
||||||
|
)"
|
||||||
|
:key="turnIdx"
|
||||||
|
class="turn_pad center"
|
||||||
|
>
|
||||||
<span
|
<span
|
||||||
class="turn_text"
|
class="turn_text"
|
||||||
:style="turnObj.style"
|
:style="turnObj.style"
|
||||||
@@ -101,7 +151,7 @@
|
|||||||
v-html="turnObj.brief"
|
v-html="turnObj.brief"
|
||||||
></span>
|
></span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row gx-1">
|
<div class="row gx-1">
|
||||||
<div class="col d-grid">
|
<div class="col d-grid">
|
||||||
@@ -200,9 +250,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import addMilliseconds from "date-fns/esm/addMilliseconds";
|
import addMilliseconds from "date-fns/esm/addMilliseconds";
|
||||||
import addMinutes from "date-fns/esm/addMinutes";
|
import addMinutes from "date-fns/esm/addMinutes";
|
||||||
import { range } from "lodash";
|
import { isString, range } from "lodash";
|
||||||
import { stringifyUrl } from "query-string";
|
import { stringifyUrl } from "query-string";
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent, ref, watch } from "vue";
|
||||||
import { formatTime } from "@util/formatTime";
|
import { formatTime } from "@util/formatTime";
|
||||||
import { joinYearMonth } from "@util/joinYearMonth";
|
import { joinYearMonth } from "@util/joinYearMonth";
|
||||||
import { mb_strwidth } from "@util/mb_strwidth";
|
import { mb_strwidth } from "@util/mb_strwidth";
|
||||||
@@ -210,6 +260,8 @@ import { parseTime } from "@util/parseTime";
|
|||||||
import { parseYearMonth } from "@util/parseYearMonth";
|
import { parseYearMonth } from "@util/parseYearMonth";
|
||||||
import { sammoAPI } from "@util/sammoAPI";
|
import { sammoAPI } from "@util/sammoAPI";
|
||||||
import { convertSearch초성 } from "./util/convertSearch초성";
|
import { convertSearch초성 } from "./util/convertSearch초성";
|
||||||
|
import DragSelect from "@/components/DragSelect.vue";
|
||||||
|
|
||||||
type commandItem = {
|
type commandItem = {
|
||||||
value: string;
|
value: string;
|
||||||
title: string;
|
title: string;
|
||||||
@@ -286,7 +338,9 @@ const searchModeKey = `sammo_searchModeOn`;
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "PartialReservedCommand",
|
name: "PartialReservedCommand",
|
||||||
|
components: {
|
||||||
|
DragSelect,
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateNow() {
|
updateNow() {
|
||||||
const serverNow = addMilliseconds(new Date(), this.timeDiff);
|
const serverNow = addMilliseconds(new Date(), this.timeDiff);
|
||||||
@@ -295,16 +349,27 @@ export default defineComponent({
|
|||||||
this.updateNow();
|
this.updateNow();
|
||||||
}, 1000 - serverNow.getMilliseconds());
|
}, 1000 - serverNow.getMilliseconds());
|
||||||
},
|
},
|
||||||
toggleTurn(turnIdx: number) {
|
toggleTurn(...turnList: number[] | string[]) {
|
||||||
if (this.turnList.has(turnIdx)) {
|
for (let turnIdx of turnList) {
|
||||||
this.turnList.delete(turnIdx);
|
if (isString(turnIdx)) {
|
||||||
} else {
|
turnIdx = parseInt(turnIdx);
|
||||||
this.turnList.add(turnIdx);
|
}
|
||||||
|
if (this.turnList.has(turnIdx)) {
|
||||||
|
this.turnList.delete(turnIdx);
|
||||||
|
} else {
|
||||||
|
this.turnList.add(turnIdx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectTurn(turnIdx: number) {
|
selectTurn(...turnList: number[] | string[]) {
|
||||||
this.turnList.clear();
|
this.turnList.clear();
|
||||||
this.turnList.add(turnIdx);
|
for (const turnIdx of turnList) {
|
||||||
|
if (isString(turnIdx)) {
|
||||||
|
this.turnList.add(parseInt(turnIdx));
|
||||||
|
} else {
|
||||||
|
this.turnList.add(turnIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
selectAll(e: Event | true) {
|
selectAll(e: Event | true) {
|
||||||
//NOTE: split 구현에 버그가 있어서, 수동으로 구분해야함
|
//NOTE: split 구현에 버그가 있어서, 수동으로 구분해야함
|
||||||
@@ -519,8 +584,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
maxTurn,
|
maxTurn,
|
||||||
flippedMaxTurn: 15,
|
|
||||||
viewMaxTurn: 15,
|
|
||||||
maxPushTurn,
|
maxPushTurn,
|
||||||
commandList,
|
commandList,
|
||||||
serverNow: formatTime(serverNowObj, "HH:mm:ss"),
|
serverNow: formatTime(serverNowObj, "HH:mm:ss"),
|
||||||
@@ -533,6 +597,34 @@ export default defineComponent({
|
|||||||
searchModeOn,
|
searchModeOn,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const flippedMaxTurn = 15;
|
||||||
|
const viewMaxTurn = ref(flippedMaxTurn);
|
||||||
|
const rowGridStyle = ref({
|
||||||
|
display: "grid",
|
||||||
|
gridTemplateRows: `repeat(${viewMaxTurn.value}, 30px)`,
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(viewMaxTurn, (val) => {
|
||||||
|
rowGridStyle.value.gridTemplateRows = `repeat(${val}, 29.4px)`;
|
||||||
|
});
|
||||||
|
|
||||||
|
function debugSel(val: unknown) {
|
||||||
|
console.log(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isDragSingle = ref(false);
|
||||||
|
const isDragToggle = ref(false);
|
||||||
|
|
||||||
|
return {
|
||||||
|
isDragSingle,
|
||||||
|
isDragToggle,
|
||||||
|
flippedMaxTurn,
|
||||||
|
viewMaxTurn,
|
||||||
|
rowGridStyle,
|
||||||
|
debugSel,
|
||||||
|
};
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
void this.reloadCommandList();
|
void this.reloadCommandList();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,7 +14,14 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
/// https://github.com/andi23rosca/drag-select-vue/blob/master/src/DragSelect.vue
|
/// https://github.com/andi23rosca/drag-select-vue/blob/master/src/DragSelect.vue
|
||||||
import { defineComponent, ref, watch, onMounted, onBeforeUnmount, PropType } from "vue";
|
import {
|
||||||
|
defineComponent,
|
||||||
|
ref,
|
||||||
|
watch,
|
||||||
|
onMounted,
|
||||||
|
onBeforeUnmount,
|
||||||
|
PropType,
|
||||||
|
} from "vue";
|
||||||
import VueTypes from "vue-types";
|
import VueTypes from "vue-types";
|
||||||
|
|
||||||
function getDimensions(p1: coord, p2: coord): rect {
|
function getDimensions(p1: coord, p2: coord): rect {
|
||||||
@@ -47,12 +54,12 @@ export default defineComponent({
|
|||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Object as PropType<Set<string>>,
|
type: Object as PropType<Set<string>>,
|
||||||
required: false,
|
required: false,
|
||||||
default: ()=>new Set(),
|
default: () => ref(new Set()),
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
emits: ["update:modelValue", "dragDone"],
|
emits: ["update:modelValue", "dragDone", "dragStart"],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const intersected = ref<Set<string>>(props.modelValue);
|
const intersected = ref<Set<string>>(props.modelValue);
|
||||||
const container = ref<HTMLElement>();
|
const container = ref<HTMLElement>();
|
||||||
@@ -60,11 +67,11 @@ export default defineComponent({
|
|||||||
watch(intersected, (val) => {
|
watch(intersected, (val) => {
|
||||||
emit("update:modelValue", val);
|
emit("update:modelValue", val);
|
||||||
});
|
});
|
||||||
watch(props.modelValue, (val)=>{
|
watch(props.modelValue, (val) => {
|
||||||
if(intersected.value === val){
|
if (intersected.value === val) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
intersected.value = val;
|
intersected.value = val;
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -102,22 +109,22 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
let dismatch = false;
|
let dismatch = false;
|
||||||
for(const oldVal of intersected.value){
|
for (const oldVal of intersected.value) {
|
||||||
if(!localIntersected.has(oldVal)){
|
if (!localIntersected.has(oldVal)) {
|
||||||
dismatch = true;
|
dismatch = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!dismatch){
|
if (!dismatch) {
|
||||||
for(const newVal of localIntersected){
|
for (const newVal of localIntersected) {
|
||||||
if(!intersected.value.has(newVal)){
|
if (!intersected.value.has(newVal)) {
|
||||||
dismatch = true;
|
dismatch = true;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(dismatch){
|
if (dismatch) {
|
||||||
intersected.value = localIntersected;
|
intersected.value = localIntersected;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function touchStart(e: TouchEvent) {
|
function touchStart(e: TouchEvent) {
|
||||||
@@ -128,8 +135,10 @@ export default defineComponent({
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
drag(e.touches[0]);
|
drag(e.touches[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isMine = false;
|
||||||
function startDrag(e: MouseEvent | Touch) {
|
function startDrag(e: MouseEvent | Touch) {
|
||||||
containerRect =uContainer.getBoundingClientRect();
|
containerRect = uContainer.getBoundingClientRect();
|
||||||
children = uContainer.children;
|
children = uContainer.children;
|
||||||
start = getCoords(e);
|
start = getCoords(e);
|
||||||
end = start;
|
end = start;
|
||||||
@@ -139,6 +148,8 @@ export default defineComponent({
|
|||||||
box.style.left = start.x + "px";
|
box.style.left = start.x + "px";
|
||||||
uContainer.prepend(box);
|
uContainer.prepend(box);
|
||||||
intersection();
|
intersection();
|
||||||
|
isMine = true;
|
||||||
|
emit("dragStart");
|
||||||
}
|
}
|
||||||
function drag(e: MouseEvent | Touch) {
|
function drag(e: MouseEvent | Touch) {
|
||||||
end = getCoords(e);
|
end = getCoords(e);
|
||||||
@@ -161,7 +172,10 @@ export default defineComponent({
|
|||||||
document.removeEventListener("mousemove", drag);
|
document.removeEventListener("mousemove", drag);
|
||||||
document.removeEventListener("touchmove", touchMove);
|
document.removeEventListener("touchmove", touchMove);
|
||||||
box.remove();
|
box.remove();
|
||||||
emit('dragDone', intersected.value);
|
if(isMine){
|
||||||
|
emit("dragDone", intersected.value);
|
||||||
|
}
|
||||||
|
isMine = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uContainer.addEventListener("mousedown", startDrag);
|
uContainer.addEventListener("mousedown", startDrag);
|
||||||
|
|||||||
Reference in New Issue
Block a user