Extract img to FilePreview component
Now images will also be displayed when they are uploaded initially
This commit is contained in:
parent
c2dfa9be83
commit
e47d6d1605
@ -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);
|
||||||
|
34
frontend/src/components/tasks/partials/file-preview.vue
Normal file
34
frontend/src/components/tasks/partials/file-preview.vue
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user