feat: improve tabs behavior & style
Signed-off-by: Luka Trovic <luka@nextcloud.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="activeTab === 'attachment'" class="section-details">
|
<div v-if="activeTabs.includes('attachment')" class="section-details">
|
||||||
<AttachmentList
|
<AttachmentList
|
||||||
:card-id="card.id"
|
:card-id="card.id"
|
||||||
:removable="true"
|
:removable="true"
|
||||||
@@ -18,9 +18,9 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
activeTab: {
|
activeTabs: {
|
||||||
type: String,
|
type: Array,
|
||||||
default: null,
|
default: () => [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
@@ -31,23 +31,23 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<div class="tab members" :class="{active: activeTab === 'members'}" @click="activeTab = 'members'">
|
<div class="tab members" :class="{active: activeTabs.includes('members')}" @click="changeActiveTab('members')">
|
||||||
<i class="icon-user icon" />
|
<i class="icon-user icon" />
|
||||||
{{ t('deck', 'Members') }}
|
{{ t('deck', 'Members') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab tags" :class="{active: activeTab === 'tags'}" @click="activeTab = 'tags'">
|
<div class="tab tags" :class="{active: activeTabs.includes('tags')}" @click="changeActiveTab('tags')">
|
||||||
<i class="icon icon-tag" />
|
<i class="icon icon-tag" />
|
||||||
{{ t('deck', 'Tags') }}
|
{{ t('deck', 'Tags') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab due-date" :class="{active: activeTab === 'duedate'}" @click="activeTab = 'duedate'">
|
<div class="tab due-date" :class="{active: activeTabs.includes('duedate')}" @click="changeActiveTab('duedate')">
|
||||||
<i class="icon icon-calendar-dark" />
|
<i class="icon icon-calendar-dark" />
|
||||||
{{ t('deck', 'Due date') }}
|
{{ t('deck', 'Due date') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab project" :class="{active: activeTab === 'project'}" @click="activeTab = 'project'">
|
<div class="tab project" :class="{active: activeTabs.includes('project')}" @click="changeActiveTab('project')">
|
||||||
<i class="icon icon-deck" />
|
<i class="icon icon-deck" />
|
||||||
{{ t('deck', 'Project') }}
|
{{ t('deck', 'Project') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab attachments" :class="{active: activeTab === 'attachment'}" @click="activeTab = 'attachment'">
|
<div class="tab attachments" :class="{active: activeTabs.includes('attachment')}" @click="changeActiveTab('attachment')">
|
||||||
<i class="icon-attach icon icon-attach-dark" />
|
<i class="icon-attach icon icon-attach-dark" />
|
||||||
{{ t('deck', 'Attachments') }}
|
{{ t('deck', 'Attachments') }}
|
||||||
</div>
|
</div>
|
||||||
@@ -56,28 +56,36 @@
|
|||||||
<div class="content-tabs">
|
<div class="content-tabs">
|
||||||
<MembersTab
|
<MembersTab
|
||||||
:card="currentCard"
|
:card="currentCard"
|
||||||
:active-tab="activeTab"
|
:active-tabs="activeTabs"
|
||||||
@click="activeTab = 'members'"
|
:current-tab="currentTab"
|
||||||
@active-tab="changeActiveTab" />
|
@click="activeTabs.push('members')"
|
||||||
|
@active-tab="changeActiveTab"
|
||||||
|
@remove-active-tab="removeActiveTab" />
|
||||||
<TagsTab
|
<TagsTab
|
||||||
:active-tab="activeTab"
|
:active-tabs="activeTabs"
|
||||||
:card="currentCard"
|
:card="currentCard"
|
||||||
@click="activeTab = 'tags'"
|
:current-tab="currentTab"
|
||||||
@active-tab="changeActiveTab" />
|
@click="activeTabs.push('tags')"
|
||||||
|
@active-tab="changeActiveTab"
|
||||||
|
@remove-active-tab="removeActiveTab" />
|
||||||
<DueDateTab
|
<DueDateTab
|
||||||
:active-tab="activeTab"
|
:active-tabs="activeTabs"
|
||||||
:card="currentCard"
|
:card="currentCard"
|
||||||
@click="activeTab = 'duedate'"
|
:current-tab="currentTab"
|
||||||
@active-tab="changeActiveTab" />
|
@click="activeTabs.push('duedate')"
|
||||||
|
@active-tab="changeActiveTab"
|
||||||
|
@remove-active-tab="removeActiveTab" />
|
||||||
<ProjectTab
|
<ProjectTab
|
||||||
:active-tab="activeTab"
|
:active-tabs="activeTabs"
|
||||||
:card="currentCard"
|
:card="currentCard"
|
||||||
@click="activeTab = 'project'"
|
:current-tab="currentTab"
|
||||||
|
@click="activeTabs.push('project')"
|
||||||
@active-tab="changeActiveTab" />
|
@active-tab="changeActiveTab" />
|
||||||
<AttachmentsTab
|
<AttachmentsTab
|
||||||
:active-tab="activeTab"
|
:active-tabs="activeTabs"
|
||||||
:card="currentCard"
|
:card="currentCard"
|
||||||
@click="activeTab = 'attachment'"
|
:current-tab="currentTab"
|
||||||
|
@click="activeTabs.push('attachment')"
|
||||||
@active-tab="changeActiveTab" />
|
@active-tab="changeActiveTab" />
|
||||||
</div>
|
</div>
|
||||||
<Description :key="currentCard.id" :card="currentCard" @change="descriptionChanged" />
|
<Description :key="currentCard.id" :card="currentCard" @change="descriptionChanged" />
|
||||||
@@ -86,29 +94,17 @@
|
|||||||
<h2 class="activities-title">
|
<h2 class="activities-title">
|
||||||
<div class="icon-activity" /> {{ t('deck', 'Activity') }}
|
<div class="icon-activity" /> {{ t('deck', 'Activity') }}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="comments">
|
<CardSidebarTabComments :card="currentCard" :tab-query="tabQuery" />
|
||||||
<Avatar :user="currentUser.uid" />
|
<ActivityList v-if="hasActivity"
|
||||||
<CommentForm v-model="newComment" @submit="createComment" />
|
filter="deck"
|
||||||
</div>
|
:object-id="currentBoard.id"
|
||||||
<div class="activities-logs">
|
object-type="deck"
|
||||||
<CommentItem v-if="replyTo"
|
type="deck" />
|
||||||
:comment="replyTo"
|
|
||||||
:reply="true"
|
|
||||||
:preview="true"
|
|
||||||
@cancel="cancelReply" />
|
|
||||||
<ul v-if="getCommentsForCard(currentCard.id).length > 0" id="commentsFeed">
|
|
||||||
<CommentItem v-for="cmt in getCommentsForCard(currentCard.id)"
|
|
||||||
:key="cmt.id"
|
|
||||||
:comment="cmt"
|
|
||||||
@doReload="loadComments" />
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Avatar } from '@nextcloud/vue'
|
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { mapState, mapGetters } from 'vuex'
|
import { mapState, mapGetters } from 'vuex'
|
||||||
import relativeDate from '../../mixins/relativeDate'
|
import relativeDate from '../../mixins/relativeDate'
|
||||||
@@ -120,24 +116,23 @@ import DueDateTab from './DueDateTab.vue'
|
|||||||
import Description from './Description.vue'
|
import Description from './Description.vue'
|
||||||
import ProjectTab from './ProjectTab.vue'
|
import ProjectTab from './ProjectTab.vue'
|
||||||
import AttachmentsTab from './AttachmentsTab.vue'
|
import AttachmentsTab from './AttachmentsTab.vue'
|
||||||
import CommentForm from './CommentForm'
|
import CardSidebarTabComments from './CardSidebarTabComments'
|
||||||
import CommentItem from './CommentItem'
|
|
||||||
import moment from '@nextcloud/moment'
|
import moment from '@nextcloud/moment'
|
||||||
|
import ActivityList from '../ActivityList'
|
||||||
|
|
||||||
const capabilities = window.OC.getCapabilities()
|
const capabilities = window.OC.getCapabilities()
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CardModal',
|
name: 'CardModal',
|
||||||
components: {
|
components: {
|
||||||
Avatar,
|
|
||||||
MembersTab,
|
MembersTab,
|
||||||
Description,
|
Description,
|
||||||
TagsTab,
|
TagsTab,
|
||||||
DueDateTab,
|
DueDateTab,
|
||||||
ProjectTab,
|
ProjectTab,
|
||||||
AttachmentsTab,
|
AttachmentsTab,
|
||||||
CommentForm,
|
CardSidebarTabComments,
|
||||||
CommentItem,
|
ActivityList,
|
||||||
},
|
},
|
||||||
filters: {
|
filters: {
|
||||||
fromNow(value) {
|
fromNow(value) {
|
||||||
@@ -169,7 +164,8 @@ export default {
|
|||||||
hasActivity: capabilities && capabilities.activity,
|
hasActivity: capabilities && capabilities.activity,
|
||||||
currentUser: getCurrentUser(),
|
currentUser: getCurrentUser(),
|
||||||
comment: '',
|
comment: '',
|
||||||
activeTab: null,
|
currentTab: null,
|
||||||
|
activeTabs: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -276,7 +272,20 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
changeActiveTab(tab) {
|
changeActiveTab(tab) {
|
||||||
this.activeTab = tab
|
this.currentTab = tab
|
||||||
|
this.activeTabs = this.activeTabs.filter((item) => !['project', 'attachment'].includes(item))
|
||||||
|
|
||||||
|
if (!this.activeTabs.includes(tab)) {
|
||||||
|
this.activeTabs.push(tab)
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
removeActiveTab(tab) {
|
||||||
|
const index = this.activeTabs.indexOf(tab)
|
||||||
|
if (index > -1) {
|
||||||
|
this.activeTabs = this.activeTabs.splice(index, 1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="activeTab === 'duedate' || (copiedCard && copiedCard.duedate)"
|
<div v-if="activeTabs.includes('duedate') || (copiedCard && copiedCard.duedate)"
|
||||||
v-show="!['project', 'attachment'].includes(activeTab)"
|
v-show="!['project', 'attachment'].includes(currentTab)"
|
||||||
class="section-details">
|
class="section-details">
|
||||||
<div @click="$emit('active-tab', 'duedate')">
|
<div @click="$emit('active-tab', 'duedate')">
|
||||||
<DatetimePicker v-model="duedate"
|
<DatetimePicker v-model="duedate"
|
||||||
@@ -20,7 +20,6 @@
|
|||||||
</Actions>
|
</Actions>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { DatetimePicker, Actions, ActionButton } from '@nextcloud/vue'
|
import { DatetimePicker, Actions, ActionButton } from '@nextcloud/vue'
|
||||||
import { mapState, mapGetters } from 'vuex'
|
import { mapState, mapGetters } from 'vuex'
|
||||||
@@ -41,9 +40,13 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
activeTab: {
|
activeTabs: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
currentTab: {
|
||||||
type: String,
|
type: String,
|
||||||
default: null,
|
default: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@@ -133,10 +136,20 @@ export default {
|
|||||||
watch: {
|
watch: {
|
||||||
card() {
|
card() {
|
||||||
this.initialize()
|
this.initialize()
|
||||||
|
if (this.copiedCard.duedate) {
|
||||||
|
this.$emit('active-tab', 'duedate')
|
||||||
|
} else {
|
||||||
|
this.$emit('remove-active-tab', 'duedate')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.initialize()
|
this.initialize()
|
||||||
|
if (this.copiedCard.duedate) {
|
||||||
|
this.$emit('active-tab', 'duedate')
|
||||||
|
} else {
|
||||||
|
this.$emit('remove-active-tab', 'duedate')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async initialize() {
|
async initialize() {
|
||||||
@@ -155,7 +168,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.section-details {
|
.section-details{
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@@ -163,7 +176,7 @@ export default {
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.section-details .mx-input {
|
.section-details .mx-input{
|
||||||
height: 36px !important;
|
height: 36px !important;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-show="!['project', 'attachment'].includes(activeTab)"
|
<div v-if="activeTabs.includes('members') || (assignedUsers && assignedUsers.length > 0)"
|
||||||
v-if="activeTab === 'members' || (assignedUsers && assignedUsers.length > 0)"
|
v-show="!['project', 'attachment'].includes(currentTab)"
|
||||||
class="section-details">
|
class="section-details">
|
||||||
<div v-if="showSelelectMembers" @mouseleave="showSelelectMembers = false">
|
<div v-if="showSelelectMembers" @mouseleave="showSelelectMembers = false">
|
||||||
<Multiselect v-if="canEdit"
|
<Multiselect v-if="canEdit"
|
||||||
@@ -65,9 +65,13 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
activeTab: {
|
activeTabs: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
currentTab: {
|
||||||
type: String,
|
type: String,
|
||||||
default: null,
|
default: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@@ -110,6 +114,13 @@ export default {
|
|||||||
card() {
|
card() {
|
||||||
this.initialize()
|
this.initialize()
|
||||||
},
|
},
|
||||||
|
assignedUsers(value) {
|
||||||
|
if (value.length > 0) {
|
||||||
|
this.$emit('active-tab', 'members')
|
||||||
|
} else {
|
||||||
|
this.$emit('remove-active-tab', 'members')
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.initialize()
|
this.initialize()
|
||||||
@@ -172,8 +183,8 @@ export default {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
width: 32px;
|
width: 34px;
|
||||||
padding: 9px;
|
padding: 5px 9px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="activeTab === 'project'" class="section-details">
|
<div v-if="activeTabs.includes('project')" class="section-details">
|
||||||
<div class="section-wrapper" @click="$emit('active-tab', 'project')">
|
<div class="section-wrapper">
|
||||||
<CollectionList v-if="card.id"
|
<CollectionList v-if="card.id"
|
||||||
:id="`${card.id}`"
|
:id="`${card.id}`"
|
||||||
:name="card.title"
|
:name="card.title"
|
||||||
@@ -19,21 +19,11 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
activeTab: {
|
activeTabs: {
|
||||||
type: String,
|
type: Array,
|
||||||
default: null,
|
default: () => [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-show="!['project', 'attachment'].includes(activeTab)"
|
<div v-if="activeTabs.includes('tags') || card.labels.length > 0"
|
||||||
v-if="activeTab === 'tags' || card.labels.length > 0"
|
v-show="!['project', 'attachment'].includes(currentTab)"
|
||||||
class="section-details">
|
class="section-details">
|
||||||
<div v-if="showSelelectTags || card.labels.length <= 0" @mouseleave="showSelelectTags = false">
|
<div v-if="showSelelectTags || card.labels.length <= 0" @mouseleave="showSelelectTags = false">
|
||||||
<Multiselect v-model="assignedLabels"
|
<Multiselect v-model="assignedLabels"
|
||||||
@@ -53,9 +53,13 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
activeTab: {
|
activeTabs: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
currentTab: {
|
||||||
type: String,
|
type: String,
|
||||||
default: null,
|
default: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@@ -74,8 +78,20 @@ export default {
|
|||||||
return [...this.currentBoard.labels].sort((a, b) => (a.title < b.title) ? -1 : 1)
|
return [...this.currentBoard.labels].sort((a, b) => (a.title < b.title) ? -1 : 1)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
card(value) {
|
||||||
|
if (value.labels.length > 0) {
|
||||||
|
this.$emit('active-tab', 'tags')
|
||||||
|
} else {
|
||||||
|
this.$emit('remove-active-tab', 'tags')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.initialize()
|
this.initialize()
|
||||||
|
if (this.card.labels.length > 0) {
|
||||||
|
this.$emit('active-tab', 'tags')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
add() {
|
add() {
|
||||||
@@ -140,11 +156,11 @@ export default {
|
|||||||
|
|
||||||
.select-tag {
|
.select-tag {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
width: 32px;
|
width: 34px;
|
||||||
padding: 5px 7px;
|
padding: 5px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tag {
|
.tag{
|
||||||
padding: 0px 5px;
|
padding: 0px 5px;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user