Move sidebar tabs to individual components
Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
@@ -21,12 +21,11 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AppSidebar v-if="currentCard !== null && currentBoard && copiedCard !== null"
|
<AppSidebar v-if="currentBoard && currentCard && copiedCard"
|
||||||
:actions="toolbarActions"
|
|
||||||
:title="currentCard.title"
|
:title="currentCard.title"
|
||||||
:subtitle="subtitle"
|
:subtitle="subtitle"
|
||||||
@close="closeSidebar">
|
@close="closeSidebar">
|
||||||
<template #action />
|
<template #secondary-actions />
|
||||||
<AppSidebarTab :order="0" name="Details" icon="icon-home">
|
<AppSidebarTab :order="0" name="Details" icon="icon-home">
|
||||||
<div class="section-wrapper">
|
<div class="section-wrapper">
|
||||||
<div v-tooltip="t('deck', 'Tags')" class="section-label icon-tag">
|
<div v-tooltip="t('deck', 'Tags')" class="section-label icon-tag">
|
||||||
@@ -104,29 +103,20 @@
|
|||||||
type="deck-card" />
|
type="deck-card" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h5>Description</h5>
|
<h5>{{ t('deck', 'Description') }}</h5>
|
||||||
<VueEasymde ref="markdownEditor" v-model="copiedCard.description" :configs="mdeConfig" />
|
<VueEasymde ref="markdownEditor" v-model="copiedCard.description" :configs="mdeConfig" />
|
||||||
</AppSidebarTab>
|
</AppSidebarTab>
|
||||||
<AppSidebarTab :order="1" name="Attachments" icon="icon-attach">
|
|
||||||
{{ currentCard.attachments }}
|
<AppSidebarTab :order="1" :name="t('deck', 'Attachments')" icon="icon-attach">
|
||||||
<button class="icon-upload" @click="clickAddNewAttachmment()">
|
<CardSidebarTabAttachments :card="currentCard" />
|
||||||
{{ t('deck', 'Upload attachment') }}
|
|
||||||
</button>
|
|
||||||
</AppSidebarTab>
|
</AppSidebarTab>
|
||||||
|
|
||||||
<AppSidebarTab :order="2" name="Comments" icon="icon-comment">
|
<AppSidebarTab :order="2" :name="t('deck', 'Comments')" icon="icon-comment">
|
||||||
<CommentsTabSidebar :card="currentCard" />
|
<CardSidebarTabComments :card="currentCard" />
|
||||||
</AppSidebarTab>
|
</AppSidebarTab>
|
||||||
|
|
||||||
<AppSidebarTab :order="3" name="Timeline" icon="icon-activity">
|
<AppSidebarTab :order="3" :name="t('deck', 'Timeline')" icon="icon-activity">
|
||||||
<div v-if="isLoading" class="icon icon-loading" />
|
<CardSidebarTabActivity :card="currentCard" />
|
||||||
<ActivityEntry v-for="entry in cardActivity"
|
|
||||||
v-else
|
|
||||||
:key="entry.activity_id"
|
|
||||||
:activity="entry" />
|
|
||||||
<button v-if="activityLoadMore" @click="loadMore">
|
|
||||||
Load More
|
|
||||||
</button>
|
|
||||||
</AppSidebarTab>
|
</AppSidebarTab>
|
||||||
</AppSidebar>
|
</AppSidebar>
|
||||||
</template>
|
</template>
|
||||||
@@ -141,15 +131,16 @@ import { mapState } from 'vuex'
|
|||||||
import VueEasymde from 'vue-easymde/dist/VueEasyMDE.common'
|
import VueEasymde from 'vue-easymde/dist/VueEasyMDE.common'
|
||||||
import { Actions } from '@nextcloud/vue/dist/Components/Actions'
|
import { Actions } from '@nextcloud/vue/dist/Components/Actions'
|
||||||
import { ActionButton } from '@nextcloud/vue/dist/Components/ActionButton'
|
import { ActionButton } from '@nextcloud/vue/dist/Components/ActionButton'
|
||||||
import ActivityEntry from '../ActivityEntry'
|
|
||||||
import Color from '../../mixins/color'
|
import Color from '../../mixins/color'
|
||||||
import { CollectionList } from 'nextcloud-vue-collections'
|
import { CollectionList } from 'nextcloud-vue-collections'
|
||||||
import CommentsTabSidebar from './CommentsTabSidebar'
|
|
||||||
|
import CardSidebarTabAttachments from './CardSidebarTabAttachments'
|
||||||
|
import CardSidebarTabComments from './CardSidebarTabComments'
|
||||||
|
import CardSidebarTabActivity from './CardSidebarTabActivity'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CardSidebar',
|
name: 'CardSidebar',
|
||||||
components: {
|
components: {
|
||||||
ActivityEntry,
|
|
||||||
AppSidebar,
|
AppSidebar,
|
||||||
AppSidebarTab,
|
AppSidebarTab,
|
||||||
Multiselect,
|
Multiselect,
|
||||||
@@ -159,7 +150,9 @@ export default {
|
|||||||
ActionButton,
|
ActionButton,
|
||||||
Avatar,
|
Avatar,
|
||||||
CollectionList,
|
CollectionList,
|
||||||
CommentsTabSidebar,
|
CardSidebarTabAttachments,
|
||||||
|
CardSidebarTabComments,
|
||||||
|
CardSidebarTabActivity,
|
||||||
},
|
},
|
||||||
mixins: [
|
mixins: [
|
||||||
Color,
|
Color,
|
||||||
@@ -174,7 +167,6 @@ export default {
|
|||||||
return {
|
return {
|
||||||
assignedUsers: null,
|
assignedUsers: null,
|
||||||
addedLabelToCard: null,
|
addedLabelToCard: null,
|
||||||
isLoading: false,
|
|
||||||
copiedCard: null,
|
copiedCard: null,
|
||||||
allLabels: null,
|
allLabels: null,
|
||||||
desc: null,
|
desc: null,
|
||||||
@@ -187,20 +179,12 @@ export default {
|
|||||||
},
|
},
|
||||||
lastModifiedRelative: null,
|
lastModifiedRelative: null,
|
||||||
lastCreatedRemative: null,
|
lastCreatedRemative: null,
|
||||||
params: {
|
|
||||||
type: 'filter',
|
|
||||||
since: 0,
|
|
||||||
object_type: 'deck_card',
|
|
||||||
object_id: this.id,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
currentBoard: state => state.currentBoard,
|
currentBoard: state => state.currentBoard,
|
||||||
assignableUsers: state => state.assignableUsers,
|
assignableUsers: state => state.assignableUsers,
|
||||||
cardActivity: 'activity',
|
|
||||||
activityLoadMore: 'activityLoadMore',
|
|
||||||
}),
|
}),
|
||||||
currentCard() {
|
currentCard() {
|
||||||
return this.$store.getters.cardById(this.id)
|
return this.$store.getters.cardById(this.id)
|
||||||
@@ -208,24 +192,6 @@ export default {
|
|||||||
subtitle() {
|
subtitle() {
|
||||||
return t('deck', 'Modified') + ': ' + this.lastModifiedRelative + ' ' + t('deck', 'Created') + ': ' + this.lastCreatedRemative
|
return t('deck', 'Modified') + ': ' + this.lastModifiedRelative + ' ' + t('deck', 'Created') + ': ' + this.lastCreatedRemative
|
||||||
},
|
},
|
||||||
toolbarActions() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
action: () => {
|
|
||||||
|
|
||||||
},
|
|
||||||
icon: 'icon-archive-dark',
|
|
||||||
text: t('deck', 'Assign to me'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: () => {
|
|
||||||
|
|
||||||
},
|
|
||||||
icon: 'icon-archive',
|
|
||||||
text: t('deck', (this.showArchived ? 'Unarchive card' : 'Archive card')),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'currentCard': {
|
'currentCard': {
|
||||||
@@ -243,9 +209,6 @@ export default {
|
|||||||
|
|
||||||
this.desc = this.currentCard.description
|
this.desc = this.currentCard.description
|
||||||
this.updateRelativeTimestamps()
|
this.updateRelativeTimestamps()
|
||||||
|
|
||||||
this.params.object_id = this.id
|
|
||||||
this.loadCardActivity()
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -313,23 +276,6 @@ export default {
|
|||||||
}
|
}
|
||||||
this.$store.dispatch('removeLabel', data)
|
this.$store.dispatch('removeLabel', data)
|
||||||
},
|
},
|
||||||
loadCardActivity() {
|
|
||||||
this.isLoading = true
|
|
||||||
this.$store.dispatch('loadActivity', this.params).then(response => {
|
|
||||||
this.isLoading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
loadMore() {
|
|
||||||
const array = Object.values(this.cardActivity)
|
|
||||||
const aId = (array[array.length - 1].activity_id)
|
|
||||||
|
|
||||||
this.params.since = aId
|
|
||||||
this.loadCardActivity()
|
|
||||||
},
|
|
||||||
clickAddNewAttachmment() {
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
98
src/components/card/CardSidebarTabActivity.vue
Normal file
98
src/components/card/CardSidebarTabActivity.vue
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
<!--
|
||||||
|
- @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net>
|
||||||
|
-
|
||||||
|
- @author Julius Härtl <jus@bitgrid.net>
|
||||||
|
-
|
||||||
|
- @license GNU AGPL version 3 or any later version
|
||||||
|
-
|
||||||
|
- This program is free software: you can redistribute it and/or modify
|
||||||
|
- it under the terms of the GNU Affero General Public License as
|
||||||
|
- published by the Free Software Foundation, either version 3 of the
|
||||||
|
- License, or (at your option) any later version.
|
||||||
|
-
|
||||||
|
- This program is distributed in the hope that it will be useful,
|
||||||
|
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
- GNU Affero General Public License for more details.
|
||||||
|
-
|
||||||
|
- You should have received a copy of the GNU Affero General Public License
|
||||||
|
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div v-if="isLoading" class="icon icon-loading" />
|
||||||
|
<div v-else>
|
||||||
|
<ActivityEntry v-for="entry in cardActivity"
|
||||||
|
|
||||||
|
:key="entry.activity_id"
|
||||||
|
:activity="entry" />
|
||||||
|
</div>
|
||||||
|
<button v-if="activityLoadMore" @click="loadMore">
|
||||||
|
Load More
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ActivityEntry from '../ActivityEntry'
|
||||||
|
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CardSidebarTabActivity',
|
||||||
|
components: {
|
||||||
|
ActivityEntry,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
card: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
id: 'activity',
|
||||||
|
isLoading: false,
|
||||||
|
params: {
|
||||||
|
type: 'filter',
|
||||||
|
since: 0,
|
||||||
|
object_type: 'deck_card',
|
||||||
|
object_id: this.id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
currentBoard: state => state.currentBoard,
|
||||||
|
assignableUsers: state => state.assignableUsers,
|
||||||
|
cardActivity: 'activity',
|
||||||
|
activityLoadMore: 'activityLoadMore',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.params.object_id = this.card.id
|
||||||
|
this.loadCardActivity()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadCardActivity() {
|
||||||
|
this.isLoading = true
|
||||||
|
this.$store.dispatch('loadActivity', this.params).then(response => {
|
||||||
|
this.isLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loadMore() {
|
||||||
|
const array = Object.values(this.cardActivity)
|
||||||
|
const aId = (array[array.length - 1].activity_id)
|
||||||
|
|
||||||
|
this.params.since = aId
|
||||||
|
this.loadCardActivity()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
51
src/components/card/CardSidebarTabAttachments.vue
Normal file
51
src/components/card/CardSidebarTabAttachments.vue
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<!--
|
||||||
|
- @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net>
|
||||||
|
-
|
||||||
|
- @author Julius Härtl <jus@bitgrid.net>
|
||||||
|
-
|
||||||
|
- @license GNU AGPL version 3 or any later version
|
||||||
|
-
|
||||||
|
- This program is free software: you can redistribute it and/or modify
|
||||||
|
- it under the terms of the GNU Affero General Public License as
|
||||||
|
- published by the Free Software Foundation, either version 3 of the
|
||||||
|
- License, or (at your option) any later version.
|
||||||
|
-
|
||||||
|
- This program is distributed in the hope that it will be useful,
|
||||||
|
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
- GNU Affero General Public License for more details.
|
||||||
|
-
|
||||||
|
- You should have received a copy of the GNU Affero General Public License
|
||||||
|
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
{{ card.attachments }}
|
||||||
|
<button class="icon-upload" @click="clickAddNewAttachmment()">
|
||||||
|
{{ t('deck', 'Upload attachment') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'CardSidebarTabAttachments',
|
||||||
|
props: {
|
||||||
|
card: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clickAddNewAttachmment() {
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul id="commentsFeed" v-if="comments[card.id] && comments[card.id].length > 0">
|
<ul v-if="comments[card.id] && comments[card.id].length > 0" id="commentsFeed">
|
||||||
<CommentItem v-for="comment in comments[card.id]"
|
<CommentItem v-for="comment in comments[card.id]"
|
||||||
:key="comment.id"
|
:key="comment.id"
|
||||||
:comment="comment"
|
:comment="comment"
|
||||||
@@ -46,8 +46,8 @@
|
|||||||
</a>
|
</a>
|
||||||
</ul>
|
</ul>
|
||||||
<div v-else-if="isLoading" class="icon icon-loading" />
|
<div v-else-if="isLoading" class="icon icon-loading" />
|
||||||
<div class="emptycontent" v-else>
|
<div v-else class="emptycontent">
|
||||||
<div class="icon-comment"></div>
|
<div class="icon-comment" />
|
||||||
<p>Keine Kommentare bisher. Beginne die Diskussion!</p>
|
<p>Keine Kommentare bisher. Beginne die Diskussion!</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -64,7 +64,7 @@ import { Avatar } from '@nextcloud/vue'
|
|||||||
import CommentItem from './CommentItem'
|
import CommentItem from './CommentItem'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CommentsTabSidebar',
|
name: 'CardSidebarTabComments',
|
||||||
components: {
|
components: {
|
||||||
Avatar,
|
Avatar,
|
||||||
CommentItem,
|
CommentItem,
|
||||||
44
src/css/comments.scss
Normal file
44
src/css/comments.scss
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
.comment-form form {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.editor__content::v-deep {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-left: 44px;
|
||||||
|
|
||||||
|
.ProseMirror {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"] {
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 13px;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
opacity: .3;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.comment {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.comment--header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--color-text-light);
|
||||||
|
|
||||||
|
.username {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment--content {
|
||||||
|
margin-left: 44px;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user