1
0

Extract img to FilePreview component

Now images will also be displayed when they are uploaded initially
This commit is contained in:
Elscrux 2024-04-26 19:05:10 +02:00
parent c2dfa9be83
commit e47d6d1605
2 changed files with 132 additions and 97 deletions

View File

@ -27,89 +27,91 @@
v-if="attachments.length > 0" v-if="attachments.length > 0"
class="files" class="files"
> >
<!-- FIXME: don't use a for element that wraps other links / buttons <table class="table table-striped">
Instead: overlay element with button that is inside. <tr
--> v-for="a in attachments"
<a :key="a.id"
v-for="a in attachments" class="clickable"
:key="a.id" @click="viewOrDownload(a)"
class="attachment" >
@click="viewOrDownload(a)" <td class="preview-column">
> <FilePreview
<div class="filename"> v-if="canPreview(a)"
{{ a.file.name }} class="attachment-preview"
<span :model-value="a"
v-if="task.coverImageAttachmentId === a.id" />
class="is-task-cover" </td>
> <td>
{{ $t('task.attachment.usedAsCover') }} <div class="filename">
</span> {{ a.file.name }}
</div> <span
<div class="info"> v-if="task.coverImageAttachmentId === a.id"
<p class="attachment-info-meta"> class="is-task-cover"
<i18n-t >
keypath="task.attachment.createdBy" {{ $t('task.attachment.usedAsCover') }}
scope="global"
>
<span v-tooltip="formatDateLong(a.created)">
{{ formatDateSince(a.created) }}
</span> </span>
<User </div>
:avatar-size="24" <div class="info">
:user="a.createdBy" <p class="attachment-info-meta">
:is-inline="true" <i18n-t
/> keypath="task.attachment.createdBy"
</i18n-t> scope="global"
<span> >
{{ getHumanSize(a.file.size) }} <span v-tooltip="formatDateLong(a.created)">
</span> {{ formatDateSince(a.created) }}
<span v-if="a.file.mime"> </span>
{{ a.file.mime }} <User
</span> :avatar-size="24"
</p> :user="a.createdBy"
<img :is-inline="true"
v-if="canPreview(a)" />
:src="blobUrls.get(a.id)" </i18n-t>
style="height: 20vh; min-height: 100px" <span>
alt="" {{ getHumanSize(a.file.size) }}
> </span>
<p> <span v-if="a.file.mime">
<BaseButton {{ a.file.mime }}
v-tooltip="$t('task.attachment.downloadTooltip')" </span>
class="attachment-info-meta-button" </p>
@click.prevent.stop="downloadAttachment(a)" <p>
> <BaseButton
{{ $t('misc.download') }} v-tooltip="$t('task.attachment.downloadTooltip')"
</BaseButton> class="attachment-info-meta-button"
<BaseButton @click.prevent.stop="downloadAttachment(a)"
v-tooltip="$t('task.attachment.copyUrlTooltip')" >
class="attachment-info-meta-button" {{ $t('misc.download') }}
@click.stop="copyUrl(a)" </BaseButton>
> <BaseButton
{{ $t('task.attachment.copyUrl') }} v-tooltip="$t('task.attachment.copyUrlTooltip')"
</BaseButton> class="attachment-info-meta-button"
<BaseButton @click.stop="copyUrl(a)"
v-if="editEnabled" >
v-tooltip="$t('task.attachment.deleteTooltip')" {{ $t('task.attachment.copyUrl') }}
class="attachment-info-meta-button" </BaseButton>
@click.prevent.stop="setAttachmentToDelete(a)" <BaseButton
> v-if="editEnabled"
{{ $t('misc.delete') }} v-tooltip="$t('task.attachment.deleteTooltip')"
</BaseButton> class="attachment-info-meta-button"
<BaseButton @click.prevent.stop="setAttachmentToDelete(a)"
v-if="editEnabled" >
class="attachment-info-meta-button" {{ $t('misc.delete') }}
@click.prevent.stop="setCoverImage(task.coverImageAttachmentId === a.id ? null : a)" </BaseButton>
> <BaseButton
{{ v-if="editEnabled"
task.coverImageAttachmentId === a.id class="attachment-info-meta-button"
? $t('task.attachment.unsetAsCover') @click.prevent.stop="setCoverImage(task.coverImageAttachmentId === a.id ? null : a)"
: $t('task.attachment.setAsCover') >
}} {{
</BaseButton> task.coverImageAttachmentId === a.id
</p> ? $t('task.attachment.unsetAsCover')
</div> : $t('task.attachment.setAsCover')
</a> }}
</BaseButton>
</p>
</div>
</td>
</tr>
</table>
</div> </div>
<x-button <x-button
@ -174,7 +176,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import {ref, shallowReactive, computed, onMounted} from 'vue' import {ref, shallowReactive, computed} from 'vue'
import {useDropZone} from '@vueuse/core' import {useDropZone} from '@vueuse/core'
import User from '@/components/misc/user.vue' import User from '@/components/misc/user.vue'
@ -194,6 +196,7 @@ import {useCopyToClipboard} from '@/composables/useCopyToClipboard'
import {error, success} from '@/message' import {error, success} from '@/message'
import {useTaskStore} from '@/stores/tasks' import {useTaskStore} from '@/stores/tasks'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import FilePreview from '@/components/tasks/partials/file-preview.vue'
const { const {
task, task,
@ -228,20 +231,6 @@ function downloadAttachment(attachment: IAttachment) {
const filesRef = ref<HTMLInputElement | null>(null) const filesRef = ref<HTMLInputElement | null>(null)
const blobUrls = ref<Map<number, string>>(new Map())
onMounted(() => {
fetchBlobUrls(attachments.value as IAttachment[])
})
async function fetchBlobUrls(attachments: IAttachment[]) {
for (const attachment of attachments) {
const blobUrl = await attachmentService.getBlobUrl(attachment)
if (canPreview(attachment)) {
blobUrls.value.set(attachment.id, blobUrl)
}
}
}
function uploadNewAttachment() { function uploadNewAttachment() {
const files = filesRef.value?.files const files = filesRef.value?.files
@ -458,6 +447,18 @@ async function setCoverImage(attachment: IAttachment | null) {
} }
} }
.preview-column {
max-width: 75px;
}
.attachment-preview {
max-height: 75px;
}
.clickable {
cursor: pointer;
}
.is-task-cover { .is-task-cover {
background: var(--primary); background: var(--primary);
color: var(--white); color: var(--white);

View File

@ -0,0 +1,34 @@
<template>
<img
:src="blobUrl"
alt="Attachment preview"
>
</template>
<script setup lang="ts">
import {type PropType, ref, shallowReactive, watchEffect} from 'vue'
import AttachmentService from '@/services/attachment'
import type { IAttachment } from '@/modelTypes/IAttachment'
const props = defineProps({
modelValue: {
type: Object as PropType<IAttachment>,
default: undefined,
},
})
const attachmentService = shallowReactive(new AttachmentService())
const blobUrl = ref<string | undefined>(undefined)
watchEffect(async () => {
if (props.modelValue) {
blobUrl.value = await attachmentService.getBlobUrl(props.modelValue)
}
})
</script>
<style scoped lang="scss">
img {
border-radius: 0.5rem;
}
</style>