@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
140
src/components/card/TagsTab.vue
Normal file
140
src/components/card/TagsTab.vue
Normal 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>
|
||||
@@ -135,7 +135,7 @@ export default {
|
||||
},
|
||||
activeBoards() {
|
||||
return this.$store.getters.boards.filter((item) => item.deletedAt === 0 && item.archived === false)
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openCard() {
|
||||
|
||||
Reference in New Issue
Block a user