Skip to content

Commit 0b471b8

Browse files
authored
Merge pull request #5035 from jszeibert/enh/CardCover
Card Cover Images
2 parents bf28940 + 24b7c23 commit 0b471b8

4 files changed

Lines changed: 126 additions & 1 deletion

File tree

src/components/Controls.vue

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,12 @@
208208
<ArrowCollapseVerticalIcon slot="icon" :size="20" decorative />
209209
{{ t('deck', 'Toggle compact mode') }}
210210
</NcActionButton>
211+
<NcActionButton @click="toggleShowCardCover">
212+
<template #icon>
213+
<ImageIcon :size="20" decorative />
214+
</template>
215+
{{ showCardCover ? t('deck', 'Hide card cover images') : t('deck', 'Show card cover images') }}
216+
</NcActionButton>
211217
</NcActions>
212218
<!-- FIXME: NcActionRouter currently doesn't work as an inline action -->
213219
<NcActions>
@@ -226,6 +232,7 @@ import { mapState, mapGetters } from 'vuex'
226232
import { NcActions, NcActionButton, NcAvatar, NcButton, NcPopover, NcModal } from '@nextcloud/vue'
227233
import labelStyle from '../mixins/labelStyle.js'
228234
import ArchiveIcon from 'vue-material-design-icons/Archive.vue'
235+
import ImageIcon from 'vue-material-design-icons/ImageMultiple.vue'
229236
import FilterIcon from 'vue-material-design-icons/Filter.vue'
230237
import FilterOffIcon from 'vue-material-design-icons/FilterOff.vue'
231238
import ArrowCollapseVerticalIcon from 'vue-material-design-icons/ArrowCollapseVertical.vue'
@@ -245,6 +252,7 @@ export default {
245252
NcPopover,
246253
NcAvatar,
247254
ArchiveIcon,
255+
ImageIcon,
248256
FilterIcon,
249257
FilterOffIcon,
250258
ArrowCollapseVerticalIcon,
@@ -285,6 +293,7 @@ export default {
285293
]),
286294
...mapState({
287295
compactMode: state => state.compactMode,
296+
showCardCover: state => state.showCardCover,
288297
searchQuery: state => state.searchQuery,
289298
}),
290299
detailsRoute() {
@@ -339,6 +348,9 @@ export default {
339348
toggleCompactMode() {
340349
this.$store.dispatch('toggleCompactMode')
341350
},
351+
toggleShowCardCover() {
352+
this.$store.dispatch('toggleShowCardCover')
353+
},
342354
toggleShowArchived() {
343355
this.$store.dispatch('toggleShowArchived')
344356
this.showArchived = !this.showArchived

src/components/cards/CardCover.vue

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<!--
2+
- @copyright Copyright (c) 2023 Johannes Szeibert <johannes@szeibert.de>
3+
-
4+
- @author Johannes Szeibert <johannes@szeibert.de>
5+
-
6+
- @license GNU AGPL version 3 or any later version
7+
-
8+
- This program is free software: you can redistribute it and/or modify
9+
- it under the terms of the GNU Affero General Public License as
10+
- published by the Free Software Foundation, either version 3 of the
11+
- License, or (at your option) any later version.
12+
-
13+
- This program is distributed in the hope that it will be useful,
14+
- but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
- GNU Affero General Public License for more details.
17+
-
18+
- You should have received a copy of the GNU Affero General Public License
19+
- along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
-
21+
-->
22+
23+
<template>
24+
<div v-if="cardId && ( attachments.length > 0 )" class="card-cover">
25+
<div v-for="(attachment, index) in attachments"
26+
:key="attachment.id"
27+
:class="['image-wrapper', { 'rounded-left': index === 0 }, { 'rounded-right': index === attachments.length - 1 }]"
28+
:style="{ backgroundImage: `url(${attachmentPreview(attachment)})` }" />
29+
</div>
30+
</template>
31+
<script>
32+
import { mapActions } from 'vuex'
33+
import { generateUrl } from '@nextcloud/router'
34+
export default {
35+
name: 'CardCover',
36+
props: {
37+
cardId: {
38+
type: Number,
39+
required: true,
40+
},
41+
},
42+
computed: {
43+
attachments() {
44+
return [...this.$store.getters.attachmentsByCard(this.cardId)]
45+
// Filter deleted and hasPreview
46+
.filter(attachment => attachment.deletedAt >= 0 && attachment.extendedData.hasPreview)
47+
// sort by id (same as in AttachmentList) to get Newest
48+
.sort((a, b) => b.id - a.id)
49+
// limit to 3 like with android Deck app
50+
.slice(0, 3)
51+
},
52+
attachmentPreview() {
53+
// FIXME find a better way to get the stack-width
54+
const stackWidth = getComputedStyle(document.documentElement).getPropertyValue('--stack-width').trim()
55+
const x = Math.ceil(parseInt(stackWidth) / this.attachments.length) | 260
56+
const y = 100
57+
return attachment => (
58+
// The core preview provider is a bit strange at times, providing much larger than needed images
59+
// when cropping is enabled. Therefore use a=1 to not crop the image and let css handle the overflow
60+
attachment.extendedData.fileid ? generateUrl(`/core/preview?fileId=${attachment.extendedData.fileid}&x=${x}&y=${y}&a=1`) : null
61+
)
62+
},
63+
},
64+
watch: {
65+
cardId: {
66+
immediate: true,
67+
handler() {
68+
if (this.$store.getters.cardById(this.cardId)?.attachmentCount > 0) {
69+
this.fetchAttachments(this.cardId)
70+
}
71+
},
72+
},
73+
},
74+
methods: {
75+
...mapActions([
76+
'fetchAttachments',
77+
]),
78+
},
79+
}
80+
</script>
81+
82+
<style lang="scss" scoped>
83+
@import '../../css/variables';
84+
85+
.card-cover {
86+
height: 100px;
87+
display: flex;
88+
.image-wrapper {
89+
flex: 1;
90+
position: relative;
91+
background-size: cover;
92+
background-repeat: no-repeat;
93+
background-position: center center;
94+
&.rounded-left {
95+
border-top-left-radius: 10px;
96+
}
97+
&.rounded-right {
98+
border-top-right-radius: 10px;
99+
}
100+
}
101+
}
102+
</style>

src/components/cards/CardItem.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
<div :style="{backgroundColor: '#' + board.color}" class="board-bullet" />
3535
{{ board.title }} » {{ stack.title }}
3636
</div>
37+
<CardCover v-if="showCardCover" :card-id="card.id" />
3738
<div class="card-upper">
3839
<h3 v-if="inlineEditingBlocked">
3940
{{ card.title }}
@@ -92,10 +93,11 @@ import labelStyle from '../../mixins/labelStyle.js'
9293
import AttachmentDragAndDrop from '../AttachmentDragAndDrop.vue'
9394
import CardMenu from './CardMenu.vue'
9495
import DueDate from './badges/DueDate.vue'
96+
import CardCover from './CardCover.vue'
9597
9698
export default {
9799
name: 'CardItem',
98-
components: { CardBadges, AttachmentDragAndDrop, CardMenu, DueDate },
100+
components: { CardBadges, AttachmentDragAndDrop, CardMenu, DueDate, CardCover },
99101
directives: {
100102
ClickOutside,
101103
},
@@ -129,6 +131,7 @@ export default {
129131
compactMode: state => state.compactMode,
130132
showArchived: state => state.showArchived,
131133
currentBoard: state => state.currentBoard,
134+
showCardCover: state => state.showCardCover,
132135
}),
133136
...mapGetters([
134137
'isArchived',

src/store/main.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export default new Vuex.Store({
6262
showArchived: false,
6363
navShown: localStorage.getItem('deck.navShown') === null || localStorage.getItem('deck.navShown') === 'true',
6464
compactMode: localStorage.getItem('deck.compactMode') === 'true',
65+
showCardCover: localStorage.getItem('deck.showCardCover') === 'true',
6566
sidebarShown: false,
6667
currentBoard: null,
6768
currentCard: null,
@@ -229,6 +230,10 @@ export default new Vuex.Store({
229230
state.compactMode = !state.compactMode
230231
localStorage.setItem('deck.compactMode', state.compactMode)
231232
},
233+
toggleShowCardCover(state) {
234+
state.showCardCover = !state.showCardCover
235+
localStorage.setItem('deck.showCardCover', state.showCardCover)
236+
},
232237
setBoards(state, boards) {
233238
state.boards = boards
234239
},
@@ -439,6 +444,9 @@ export default new Vuex.Store({
439444
toggleCompactMode({ commit }) {
440445
commit('toggleCompactMode')
441446
},
447+
toggleShowCardCover({ commit }) {
448+
commit('toggleShowCardCover')
449+
},
442450
setCurrentBoard({ commit }, board) {
443451
commit('setCurrentBoard', board)
444452
},

0 commit comments

Comments
 (0)