add tags tab

Signed-off-by: Luka Trovic <luka@nextcloud.com>
This commit is contained in:
Luka Trovic
2022-01-31 15:51:47 +01:00
parent 3ad4fbd96c
commit 427f960c80
4 changed files with 167 additions and 8 deletions

View File

@@ -31,11 +31,11 @@
</p>
</div>
<div class="tabs">
<div class="tab members" :class="{active: 'members'}">
<div class="tab members" :class="{active: activeTab === 'members'}" @click="activeTab = 'members'">
<i class="icon-user icon" />
Members
</div>
<div class="tab tags">
<div class="tab tags" :class="{active: activeTab === 'tags'}" @click="activeTab = 'tags'">
<i class="icon icon-tag" />
Tags
</div>
@@ -53,7 +53,10 @@
</div>
</div>
<div class="content">
<MembersTab :card="currentCard" />
<div class="content-tabs">
<MembersTab :card="currentCard" @click="activeTab = 'members'" @active-tab="changeActiveTab" />
<TagsTab :card="currentCard" @click="activeTab = 'tags'" @active-tab="changeActiveTab" />
</div>
<Description :key="currentCard.id" :card="currentCard" @change="descriptionChanged" />
</div>
<div class="activities">
@@ -84,13 +87,14 @@ import relativeDate from '../../mixins/relativeDate'
import { showError } from '@nextcloud/dialogs'
import { getCurrentUser } from '@nextcloud/auth'
import MembersTab from './MembersTab.vue'
import TagsTab from './TagsTab.vue'
import Description from './Description.vue'
const capabilities = window.OC.getCapabilities()
export default {
name: 'CardModal',
components: { Avatar, MembersTab, Description },
components: { Avatar, MembersTab, Description, TagsTab },
mixins: [relativeDate],
props: {
id: {
@@ -179,14 +183,25 @@ export default {
showModal() {
this.$store.dispatch('setConfig', { cardDetailsInModal: true })
},
closeModal() {
this.$store.dispatch('setConfig', { cardDetailsInModal: false })
},
changeActiveTab(tab) {
this.activeTab = tab
},
},
}
</script>
<style lang="scss" scoped>
.content-tabs {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
align-items: center;
}
.icon-flash-black {
background-image: url(../../../img/flash-black.svg);
width: 15px;

View File

@@ -32,16 +32,16 @@
</div>
</div>
<template v-else>
<div class="members" @click="showSelelectMembers = true">
<div class="members">
<Avatar v-for="option in assignedUsers"
:key="option.primaryKey"
:user="option.uid"
:display-name="option.displayname"
:is-no-user="option.isNoUser"
:size="32" />
<div class="button new select-member-btn">
<div class="button new select-member-btn" @click="selectMembers">
<span class="icon icon-add" />
<span class="hidden-visually"></span>
<span class="hidden-visually" />
</div>
</div>
</template>
@@ -109,6 +109,10 @@ export default {
this.initialize()
},
methods: {
selectMembers() {
this.showSelelectMembers = true
this.$emit('active-tab', 'members')
},
removeUserFromCard(user) {
this.$store.dispatch('removeUserFromCard', {
card: this.copiedCard,

View File

@@ -0,0 +1,140 @@
<template>
<div class="section-details">
<div v-if="showSelelectTags" @mouseleave="showSelelectTags = false">
<Multiselect v-model="assignedLabels"
:multiple="true"
:disabled="!canEdit"
:options="labelsSorted"
:placeholder="t('deck', 'Assign a tag to this card…')"
:taggable="true"
label="title"
track-by="id"
@select="addLabelToCard"
@remove="removeLabelFromCard">
<template #option="scope">
<div :style="{ backgroundColor: '#' + scope.option.color, color: textColor(scope.option.color)}" class="tag">
{{ scope.option.title }}
</div>
</template>
<template #tag="scope">
<div :style="{ backgroundColor: '#' + scope.option.color, color: textColor(scope.option.color)}" class="tag">
{{ scope.option.title }}
</div>
</template>
</Multiselect>
</div>
<div v-else-if="card.labels.length > 0" class="labels">
<div v-for="label in card.labels"
:key="label.id"
:style="labelStyle(label)"
class="labels-item">
<span @click.stop="applyLabelFilter(label)">{{ label.title }}</span>
</div>
<div class="button new select-tag" @click="add">
<span class="icon icon-add" />
<span class="hidden-visually" />
</div>
</div>
</div>
</template>
<script>
import { Multiselect } from '@nextcloud/vue'
import { mapState, mapGetters } from 'vuex'
import Color from '../../mixins/color'
import labelStyle from '../../mixins/labelStyle'
export default {
components: { Multiselect },
mixins: [Color, labelStyle],
props: {
card: {
type: Object,
default: null,
},
},
data() {
return {
assignedLabels: null,
showSelelectTags: false,
copiedCard: null,
}
},
computed: {
...mapState({
currentBoard: state => state.currentBoard,
}),
...mapGetters(['canEdit']),
labelsSorted() {
return [...this.currentBoard.labels].sort((a, b) => (a.title < b.title) ? -1 : 1)
},
},
mounted() {
this.initialize()
},
methods: {
add() {
this.showSelelectTags = true
this.$emit('active-tab', 'tags')
},
async initialize() {
if (!this.card) {
return
}
this.copiedCard = JSON.parse(JSON.stringify(this.card))
this.assignedLabels = [...this.card.labels].sort((a, b) => (a.title < b.title) ? -1 : 1)
},
openCard() {
const boardId = this.card && this.card.boardId ? this.card.boardId : this.$route.params.id
this.$router.push({ name: 'card', params: { id: boardId, cardId: this.card.id } }).catch(() => {})
},
addLabelToCard(newLabel) {
this.copiedCard.labels.push(newLabel)
const data = {
card: this.copiedCard,
labelId: newLabel.id,
}
this.$store.dispatch('addLabel', data)
},
removeLabelFromCard(removedLabel) {
const removeIndex = this.copiedCard.labels.findIndex((label) => {
return label.id === removedLabel.id
})
if (removeIndex !== -1) {
this.copiedCard.labels.splice(removeIndex, 1)
}
const data = {
card: this.copiedCard,
labelId: removedLabel.id,
}
this.$store.dispatch('removeLabel', data)
},
},
}
</script>
<style lang="scss" scoped>
.labels {
display: flex;
justify-content: flex-start;
align-items: center;
&-item {
border-radius: 5px;
margin-right: 5px;
min-width: 110px;
height: 32px;
display: flex;
justify-content: center;
align-items: center;
}
}
.select-tag {
height: 32px;
width: 32px;
padding: 5px 7px;
}
</style>

View File

@@ -135,7 +135,7 @@ export default {
},
activeBoards() {
return this.$store.getters.boards.filter((item) => item.deletedAt === 0 && item.archived === false)
}
},
},
methods: {
openCard() {