feat: project and comments tabs
Signed-off-by: Luka Trovic <luka@nextcloud.com>
This commit is contained in:
@@ -157,8 +157,7 @@ export default {
|
||||
|
||||
.modal__card {
|
||||
min-width: 320px;
|
||||
width: 50vw;
|
||||
max-width: 800px;
|
||||
width: 100%;
|
||||
min-height: 200px;
|
||||
height: auto;
|
||||
}
|
||||
@@ -171,6 +170,7 @@ export default {
|
||||
}
|
||||
|
||||
.modal-wrapper--normal .modal-container{
|
||||
width: 800px !important;
|
||||
width: 900px !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<i class="icon icon-calendar-dark" />
|
||||
Due date
|
||||
</div>
|
||||
<div class="tab project">
|
||||
<div class="tab project" :class="{active: activeTab === 'project'}" @click="activeTab = 'project'">
|
||||
<i class="icon icon-deck" />
|
||||
Project
|
||||
</div>
|
||||
@@ -57,6 +57,7 @@
|
||||
<MembersTab :card="currentCard" @click="activeTab = 'members'" @active-tab="changeActiveTab" />
|
||||
<TagsTab :card="currentCard" @click="activeTab = 'tags'" @active-tab="changeActiveTab" />
|
||||
<DueDateTab :card="currentCard" @click="activeTab = 'duedate'" @active-tab="changeActiveTab" />
|
||||
<ProjectTab :card="currentCard" @click="activeTab = 'project'" @active-tab="changeActiveTab" />
|
||||
</div>
|
||||
<Description :key="currentCard.id" :card="currentCard" @change="descriptionChanged" />
|
||||
</div>
|
||||
@@ -64,17 +65,22 @@
|
||||
<h2 class="activities-title">
|
||||
<div class="icon-flash-black" /> Activities
|
||||
</h2>
|
||||
<div class="comment">
|
||||
<div class="comments">
|
||||
<Avatar :user="currentUser.uid" />
|
||||
<input v-model="comment"
|
||||
type="text"
|
||||
:placeholder="t('deck', 'Leave a comment')"
|
||||
class="comment-input">
|
||||
<CommentForm v-model="newComment" @submit="createComment" />
|
||||
</div>
|
||||
<div class="activities-logs">
|
||||
<p class="log-item">
|
||||
<i class="icon-plus" /> You have created card Example Task 3 in list To do on board Personal
|
||||
</p>
|
||||
<CommentItem v-if="replyTo"
|
||||
:comment="replyTo"
|
||||
:reply="true"
|
||||
:preview="true"
|
||||
@cancel="cancelReply" />
|
||||
<ul v-if="getCommentsForCard(currentCard.id).length > 0" id="commentsFeed">
|
||||
<CommentItem v-for="comment in getCommentsForCard(currentCard.id)"
|
||||
:key="comment.id"
|
||||
:comment="comment"
|
||||
@doReload="loadComments" />
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -91,12 +97,24 @@ import MembersTab from './MembersTab.vue'
|
||||
import TagsTab from './TagsTab.vue'
|
||||
import DueDateTab from './DueDateTab.vue'
|
||||
import Description from './Description.vue'
|
||||
import ProjectTab from './ProjectTab.vue'
|
||||
import CommentForm from './CommentForm'
|
||||
import CommentItem from './CommentItem'
|
||||
|
||||
const capabilities = window.OC.getCapabilities()
|
||||
|
||||
export default {
|
||||
name: 'CardModal',
|
||||
components: { Avatar, MembersTab, Description, TagsTab, DueDateTab },
|
||||
components: {
|
||||
Avatar,
|
||||
MembersTab,
|
||||
Description,
|
||||
TagsTab,
|
||||
DueDateTab,
|
||||
ProjectTab,
|
||||
CommentForm,
|
||||
CommentItem,
|
||||
},
|
||||
mixins: [relativeDate],
|
||||
props: {
|
||||
id: {
|
||||
@@ -116,6 +134,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
newComment: '',
|
||||
titleEditable: false,
|
||||
titleEditing: '',
|
||||
hasActivity: capabilities && capabilities.activity,
|
||||
@@ -125,8 +144,13 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'getCommentsForCard',
|
||||
'hasMoreComments',
|
||||
]),
|
||||
...mapState({
|
||||
currentBoard: state => state.currentBoard,
|
||||
replyTo: state => state.comment.replyTo,
|
||||
}),
|
||||
...mapGetters(['canEdit', 'assignables', 'cardActions', 'stackById']),
|
||||
title() {
|
||||
@@ -156,7 +180,39 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.loadComments()
|
||||
},
|
||||
methods: {
|
||||
cancelReply() {
|
||||
this.$store.dispatch('setReplyTo', null)
|
||||
},
|
||||
async createComment(content) {
|
||||
const commentObj = {
|
||||
cardId: this.currentCard.id,
|
||||
comment: content,
|
||||
}
|
||||
await this.$store.dispatch('createComment', commentObj)
|
||||
this.$store.dispatch('setReplyTo', null)
|
||||
this.newComment = ''
|
||||
await this.loadComments()
|
||||
},
|
||||
async loadComments() {
|
||||
this.$store.dispatch('setReplyTo', null)
|
||||
this.error = null
|
||||
this.isLoading = true
|
||||
try {
|
||||
await this.$store.dispatch('fetchComments', { cardId: this.currentCard.id })
|
||||
this.isLoading = false
|
||||
if (this.currentCard.commentsUnread > 0) {
|
||||
await this.$store.dispatch('markCommentsAsRead', this.currentCard.id)
|
||||
}
|
||||
} catch (e) {
|
||||
this.isLoading = false
|
||||
console.error('Failed to fetch more comments during infinite loading', e)
|
||||
this.error = t('deck', 'Failed to load comments')
|
||||
}
|
||||
},
|
||||
descriptionChanged(newDesc) {
|
||||
this.copiedCard.description = newDesc
|
||||
},
|
||||
@@ -200,8 +256,8 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
.content-tabs {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2fr 1fr;
|
||||
align-items: center;
|
||||
grid-template-columns: 1fr 2fr 1fr 1fr;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.icon-flash-black {
|
||||
@@ -236,7 +292,7 @@ export default {
|
||||
margin-top: 100px;
|
||||
}
|
||||
|
||||
.comment {
|
||||
.comments {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
@@ -244,6 +300,10 @@ export default {
|
||||
width: 100%;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.comment-form {
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
@@ -265,8 +325,8 @@ export default {
|
||||
.tabs {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
||||
grid-gap: 30px;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { DatetimePicker } from '@nextcloud/vue'
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
@@ -137,3 +138,9 @@ export default {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.section-details {
|
||||
margin-right: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
44
src/components/card/ProjectTab.vue
Normal file
44
src/components/card/ProjectTab.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div class="section-details">
|
||||
<div class="section-wrapper" @click="$emit('active-tab', 'project')">
|
||||
<CollectionList v-if="card.id"
|
||||
:id="`${card.id}`"
|
||||
:name="card.title"
|
||||
type="deck-card" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { CollectionList } from 'nextcloud-vue-collections'
|
||||
|
||||
export default {
|
||||
components: { CollectionList },
|
||||
props: {
|
||||
card: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
#collection-select-container p {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#collection-list li {
|
||||
align-items: flex-end;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user