diff --git a/frontend/cypress/e2e/task/task.spec.ts b/frontend/cypress/e2e/task/task.spec.ts index 5b6a4db03..2988ebb4f 100644 --- a/frontend/cypress/e2e/task/task.spec.ts +++ b/frontend/cypress/e2e/task/task.spec.ts @@ -42,7 +42,7 @@ function uploadAttachmentAndVerify(taskId: number) { .selectFile('cypress/fixtures/image.jpg', {force: true}) // The input is not visible, but on purpose cy.wait('@uploadAttachment') - cy.get('.attachments .attachments .files a.attachment') + cy.get('.attachments .attachments .files button.attachment') .should('exist') } diff --git a/frontend/src/components/misc/Icon.ts b/frontend/src/components/misc/Icon.ts index 8b2d1a011..b105e271b 100644 --- a/frontend/src/components/misc/Icon.ts +++ b/frontend/src/components/misc/Icon.ts @@ -24,11 +24,15 @@ import { faCocktail, faCoffee, faCog, + faCopy, + faDownload, faEllipsisH, faEllipsisV, faExclamation, faEye, faEyeSlash, + faFile, + faFileImage, faFillDrip, faFilter, faForward, @@ -81,7 +85,6 @@ import { faCheckSquare, faClock, faComments, - faFileImage, faSave, faSquareCheck, faStar, @@ -102,6 +105,7 @@ library.add(faUnlink) library.add(faParagraph) library.add(faSquareCheck) library.add(faTable) +library.add(faFile) library.add(faFileImage) library.add(faCheckSquare) library.add(faStrikethrough) @@ -130,6 +134,8 @@ library.add(faCocktail) library.add(faCoffee) library.add(faCog) library.add(faComments) +library.add(faCopy) +library.add(faDownload) library.add(faEllipsisH) library.add(faEllipsisV) library.add(faExclamation) diff --git a/frontend/src/components/tasks/partials/attachments.vue b/frontend/src/components/tasks/partials/attachments.vue index 7aeabd531..5c6be0fe8 100644 --- a/frontend/src/components/tasks/partials/attachments.vue +++ b/frontend/src/components/tasks/partials/attachments.vue @@ -27,83 +27,87 @@ v-if="attachments.length > 0" class="files" > - - -
- {{ a.file.name }} - - {{ $t('task.attachment.usedAsCover') }} - +
+
-
-

- +

+ {{ a.file.name }} + - - {{ formatDateSince(a.created) }} + {{ $t('task.attachment.usedAsCover') }} + +
+
+

+ + + {{ formatDateSince(a.created) }} + + + + + {{ getHumanSize(a.file.size) }} - - - - {{ getHumanSize(a.file.size) }} - - - {{ a.file.mime }} - -

-

- - {{ $t('misc.download') }} - - - {{ $t('task.attachment.copyUrl') }} - - - {{ $t('misc.delete') }} - - - {{ - task.coverImageAttachmentId === a.id + + {{ a.file.mime }} + +

+

+ + + + + + + + + + + + +

+
-
+
(null) async function viewOrDownload(attachment: IAttachment) { - if (SUPPORTED_IMAGE_SUFFIX.some((suffix) => attachment.file.name.endsWith(suffix))) { + if (canPreview(attachment)) { attachmentImageBlobUrl.value = await attachmentService.getBlobUrl(attachment) } else { downloadAttachment(attachment) } } +function canPreview(attachment: IAttachment): boolean { + return SUPPORTED_IMAGE_SUFFIX.some((suffix) => attachment.file.name.endsWith(suffix)) +} + const copy = useCopyToClipboard() function copyUrl(attachment: IAttachment) { @@ -298,11 +307,18 @@ async function setCoverImage(attachment: IAttachment | null) { } .attachment { - margin-bottom: .5rem; - display: block; - transition: background-color $transition; - border-radius: $radius; + display: grid; + grid-template-columns: 9rem 1fr; + align-items: center; + width: 100%; + padding: .5rem; + + transition: background-color $transition; + background-color: transparent; + + border: transparent; + border-radius: $radius; &:hover { background-color: var(--grey-200); @@ -310,14 +326,18 @@ async function setCoverImage(attachment: IAttachment | null) { } .filename { + display: flex; + align-items: center; font-weight: bold; - margin-bottom: .25rem; + height: 2rem; color: var(--text); } .info { color: var(--grey-500); font-size: .9rem; + display: flex; + flex-direction: column; p { margin-bottom: 0; @@ -375,6 +395,12 @@ async function setCoverImage(attachment: IAttachment | null) { } } +.attachment-info-column { + display: flex; + flex-flow: column wrap; + align-self: start; +} + .attachment-info-meta { display: flex; align-items: center; @@ -406,6 +432,7 @@ async function setCoverImage(attachment: IAttachment | null) { .attachment-info-meta-button { color: var(--link); + padding: 0 .25rem; } @keyframes bounce { @@ -434,9 +461,19 @@ async function setCoverImage(attachment: IAttachment | null) { } } +.preview-column { + max-width: 8rem; + height: 5.2rem; +} + +.attachment-preview { + height: 100%; +} + .is-task-cover { background: var(--primary); color: var(--white); + margin-left: .25rem; padding: .25rem .35rem; border-radius: 4px; font-size: .75rem; diff --git a/frontend/src/components/tasks/partials/file-preview.vue b/frontend/src/components/tasks/partials/file-preview.vue new file mode 100644 index 000000000..7e2fd9a63 --- /dev/null +++ b/frontend/src/components/tasks/partials/file-preview.vue @@ -0,0 +1,58 @@ + + + + + \ No newline at end of file