diff --git a/website/client/assets/svg/drag_indicator.svg b/website/client/assets/svg/drag_indicator.svg new file mode 100644 index 0000000000..b8d36b16f0 --- /dev/null +++ b/website/client/assets/svg/drag_indicator.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/client/components/tasks/user.vue b/website/client/components/tasks/user.vue index 18fd696b3a..e9652ccabc 100644 --- a/website/client/components/tasks/user.vue +++ b/website/client/components/tasks/user.vue @@ -30,15 +30,29 @@ a.d-block(v-if="tagsType.key !== 'groups' && !editingTags", @click="editTags(tagsType.key)") {{ $t('editTags2') }} .tags-list.container .row(:class="{'no-gutters': !editingTags}") - template(v-if="editingTags && tagsType.key !== 'groups'") - .col-6(v-for="(tag, tagIndex) in tagsSnap[tagsType.key]") - .inline-edit-input-group.tag-edit-item.input-group - input.tag-edit-input.inline-edit-input.form-control(type="text", v-model="tag.name") - .input-group-append(@click="removeTag(tagIndex, tagsType.key)") - .svg-icon.destroy-icon(v-html="icons.destroy") - .col-6(v-if="tagsType.key === 'tags'") - input.new-tag-item.edit-tag-item.inline-edit-input.form-control(type="text", :placeholder="$t('newTag')", @keydown.enter="addTag($event, tagsType.key)", v-model="newTag") - template(v-else) + template(v-if="editingTags && tagsType.key === 'tags'") + draggable( + v-if="tagsType.key === 'tags'", + v-model="tagsSnap[tagsType.key]", + class="row" + ) + .col-6(v-for="(tag, tagIndex) in tagsSnap[tagsType.key]") + .inline-edit-input-group.tag-edit-item.input-group + .svg-icon.inline.drag(v-html="icons.drag") + input.tag-edit-input.inline-edit-input.form-control(type="text", v-model="tag.name") + .input-group-append(@click="removeTag(tagIndex, tagsType.key)") + .svg-icon.destroy-icon(v-html="icons.destroy") + + .col-6.dragSpace + input.new-tag-item.edit-tag-item.inline-edit-input.form-control(type="text", :placeholder="$t('newTag')", @keydown.enter="addTag($event, tagsType.key)", v-model="newTag") + template(v-if="editingTags && tagsType.key === 'challenges'") + .col-6(v-for="(tag, tagIndex) in tagsSnap[tagsType.key]") + .inline-edit-input-group.tag-edit-item.input-group + input.tag-edit-input.inline-edit-input.form-control(type="text", v-model="tag.name") + .input-group-append(@click="removeTag(tagIndex, tagsType.key)") + .svg-icon.destroy-icon(v-html="icons.destroy") + + template(v-if="!editingTags || tagsType.key === 'groups'") .col-6(v-for="(tag, tagIndex) in tagsType.tags") .custom-control.custom-checkbox input.custom-control-input( @@ -289,6 +303,23 @@ } } + .drag { + cursor: grab; + margin: auto 0; + height: 20px; + width: 20px; + + color: #C3C0C7; + + &:hover { + color: #878190; + } + } + + .dragSpace { + padding-left: 32px; + } + @media only screen and (max-width: 768px) { .filter-panel { max-width: none; @@ -310,6 +341,7 @@ import habitIcon from 'assets/svg/habit.svg'; import dailyIcon from 'assets/svg/daily.svg'; import todoIcon from 'assets/svg/todo.svg'; import rewardIcon from 'assets/svg/reward.svg'; +import dragIcon from 'assets/svg/drag_indicator.svg'; import uuid from 'uuid'; import Vue from 'vue'; @@ -320,6 +352,7 @@ import taskDefaults from 'common/script/libs/taskDefaults'; import brokenTaskModal from './brokenTaskModal'; import Item from 'client/components/inventory/item.vue'; +import draggable from 'vuedraggable'; export default { components: { @@ -328,6 +361,7 @@ export default { Item, spells, brokenTaskModal, + draggable, }, directives: { markdown, @@ -347,6 +381,7 @@ export default { daily: dailyIcon, todo: todoIcon, reward: rewardIcon, + drag: dragIcon, }), selectedTags: [], temporarilySelectedTags: [], diff --git a/website/client/store/actions/tags.js b/website/client/store/actions/tags.js index 535e0a8b22..577e411440 100644 --- a/website/client/store/actions/tags.js +++ b/website/client/store/actions/tags.js @@ -31,7 +31,7 @@ export async function updateTag (store, payload) { export async function sortTag (store, payload) { let url = 'api/v4/reorder-tags'; let response = await axios.post(url, { - tagDetails: payload.tagDetails, + tagId: payload.tagId, to: payload.to, }); return response.data.data; diff --git a/website/server/controllers/api-v3/tags.js b/website/server/controllers/api-v3/tags.js index 9b8ea2a596..4d90311257 100644 --- a/website/server/controllers/api-v3/tags.js +++ b/website/server/controllers/api-v3/tags.js @@ -182,7 +182,10 @@ api.reorderTags = { return tag.id === req.body.tagId; }); if (tagIndex === -1) throw new NotFound(res.t('tagNotFound')); - user.tags.splice(req.body.to, 0, user.tags.splice(tagIndex, 1)[0]); + + const removedItem = user.tags.splice(tagIndex, 1)[0]; + + user.tags.splice(req.body.to, 0, removedItem); await user.save(); res.respond(200, {});