feat: add display of kanban card attachment image
This commit is contained in:
parent
eae7cc5a6b
commit
3d88fdaadd
4 changed files with 91 additions and 56 deletions
|
@ -145,6 +145,7 @@ import User from '@/components/misc/user.vue'
|
|||
import BaseButton from '@/components/base/BaseButton.vue'
|
||||
|
||||
import AttachmentService from '@/services/attachment'
|
||||
import {SUPPORTED_IMAGE_SUFFIX} from '@/models/attachment'
|
||||
import type AttachmentModel from '@/models/attachment'
|
||||
import type {IAttachment} from '@/modelTypes/IAttachment'
|
||||
import type {ITask} from '@/modelTypes/ITask'
|
||||
|
@ -223,10 +224,8 @@ async function deleteAttachment() {
|
|||
}
|
||||
|
||||
const attachmentImageBlobUrl = ref<string | null>(null)
|
||||
const SUPPORTED_SUFFIX = ['.jpg', '.png', '.bmp', '.gif']
|
||||
|
||||
async function viewOrDownload(attachment: AttachmentModel) {
|
||||
if (SUPPORTED_SUFFIX.some((suffix) => attachment.file.name.endsWith(suffix)) ) {
|
||||
if (SUPPORTED_IMAGE_SUFFIX.some((suffix) => attachment.file.name.endsWith(suffix)) ) {
|
||||
attachmentImageBlobUrl.value = await attachmentService.getBlobUrl(attachment)
|
||||
} else {
|
||||
downloadAttachment(attachment)
|
||||
|
|
|
@ -11,6 +11,13 @@
|
|||
@click.ctrl="() => toggleTaskDone(task)"
|
||||
@click.meta="() => toggleTaskDone(task)"
|
||||
>
|
||||
<img
|
||||
v-if="coverImageBlobUrl"
|
||||
:src="coverImageBlobUrl"
|
||||
alt=""
|
||||
class="cover-image"
|
||||
/>
|
||||
<div class="p-2">
|
||||
<span class="task-id">
|
||||
<Done class="kanban-card__done" :is-done="task.done" variant="small"/>
|
||||
<template v-if="task.identifier === ''">
|
||||
|
@ -63,10 +70,11 @@
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref, computed} from 'vue'
|
||||
import {ref, computed, watch} from 'vue'
|
||||
import {useRouter} from 'vue-router'
|
||||
|
||||
import PriorityLabel from '@/components/tasks/partials/priorityLabel.vue'
|
||||
|
@ -77,6 +85,8 @@ import ChecklistSummary from './checklist-summary.vue'
|
|||
|
||||
import {TASK_DEFAULT_COLOR, getHexColor} from '@/models/task'
|
||||
import type {ITask} from '@/modelTypes/ITask'
|
||||
import {SUPPORTED_IMAGE_SUFFIX} from '@/models/attachment'
|
||||
import AttachmentService from '@/services/attachment'
|
||||
|
||||
import {formatDateLong, formatISO, formatDateSince} from '@/helpers/time/formatDate'
|
||||
import {colorIsDark} from '@/helpers/color/colorIsDark'
|
||||
|
@ -114,6 +124,29 @@ function openTaskDetail() {
|
|||
state: {backdropView: router.currentRoute.value.fullPath},
|
||||
})
|
||||
}
|
||||
|
||||
const coverImageBlobUrl = ref<string | null>(null)
|
||||
|
||||
async function maybeDownloadCoverImage() {
|
||||
if (!props.task.coverImageAttachmentId) {
|
||||
return
|
||||
}
|
||||
|
||||
const attachment = props.task.attachments.find(a => a.id === props.task.coverImageAttachmentId)
|
||||
if (!attachment || !SUPPORTED_IMAGE_SUFFIX.some((suffix) => attachment.file.name.endsWith(suffix))) {
|
||||
console.log('not an attachment')
|
||||
return
|
||||
}
|
||||
|
||||
const attachmentService = new AttachmentService()
|
||||
coverImageBlobUrl.value = await attachmentService.getBlobUrl(attachment)
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.task.coverImageAttachmentId,
|
||||
maybeDownloadCoverImage,
|
||||
{immediate: true},
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -125,12 +158,11 @@ $task-background: var(--white);
|
|||
cursor: pointer;
|
||||
box-shadow: var(--shadow-xs);
|
||||
display: block;
|
||||
border: 3px solid transparent;
|
||||
|
||||
font-size: .9rem;
|
||||
padding: .4rem;
|
||||
border-radius: $radius;
|
||||
background: $task-background;
|
||||
overflow: hidden;
|
||||
|
||||
&.loader-container.is-loading::after {
|
||||
width: 1.5rem;
|
||||
|
|
|
@ -11,6 +11,7 @@ import type {IBucket} from './IBucket'
|
|||
import type {IRelationKind} from '@/types/IRelationKind'
|
||||
import type {IRepeatAfter} from '@/types/IRepeatAfter'
|
||||
import type {IRepeatMode} from '@/types/IRepeatMode'
|
||||
|
||||
export interface ITask extends IAbstract {
|
||||
id: number
|
||||
title: string
|
||||
|
@ -31,8 +32,9 @@ export interface ITask extends IAbstract {
|
|||
parentTaskId: ITask['id']
|
||||
hexColor: string
|
||||
percentDone: number
|
||||
relatedTasks: Partial<Record<IRelationKind, ITask[]>>,
|
||||
relatedTasks: Partial<Record<IRelationKind, ITask[]>>
|
||||
attachments: IAttachment[]
|
||||
coverImageAttachmentId: IAttachment['id']
|
||||
identifier: string
|
||||
index: number
|
||||
isFavorite: boolean
|
||||
|
|
|
@ -5,6 +5,8 @@ import type { IUser } from '@/modelTypes/IUser'
|
|||
import type { IFile } from '@/modelTypes/IFile'
|
||||
import type { IAttachment } from '@/modelTypes/IAttachment'
|
||||
|
||||
export const SUPPORTED_IMAGE_SUFFIX = ['.jpg', '.png', '.bmp', '.gif']
|
||||
|
||||
export default class AttachmentModel extends AbstractModel<IAttachment> implements IAttachment {
|
||||
id = 0
|
||||
taskId = 0
|
||||
|
|
Loading…
Reference in a new issue