diff --git a/frontend/views/containers/chatroom/file-attachment/ChatAttachmentPreview.vue b/frontend/views/containers/chatroom/file-attachment/ChatAttachmentPreview.vue index 5735f8803..8435bda84 100644 --- a/frontend/views/containers/chatroom/file-attachment/ChatAttachmentPreview.vue +++ b/frontend/views/containers/chatroom/file-attachment/ChatAttachmentPreview.vue @@ -17,7 +17,7 @@ .c-file-name.has-ellipsis {{ entry.name }} .c-file-ext-and-size .c-file-ext {{ fileExt(entry) }} - .c-file-size(v-if='entry.size') {{ fileSize(entry) }} + .c-file-size(v-if='entry.size') {{ fileSizeDisplay(entry) }} .c-preview-img(v-else) img( @@ -38,7 +38,7 @@ .c-attachment-actions tooltip( direction='top' - :text='L("Download")' + :text='getDownloadTooltipText(entry)' ) button.is-icon-small( :aria-label='L("Download")' @@ -93,9 +93,10 @@ import sbp from '@sbp/sbp' import Tooltip from '@components/Tooltip.vue' import { MESSAGE_VARIANTS } from '@model/contracts/shared/constants.js' -import { getFileExtension, getFileType } from '@view-utils/filters.js' +import { getFileExtension, getFileType, formatBytesDecimal } from '@view-utils/filters.js' import { Secret } from '~/shared/domains/chelonia/Secret.js' import { OPEN_MODAL } from '@utils/events.js' +import { L } from '@common/common.js' export default { name: 'ChatAttachmentPreview', @@ -156,8 +157,13 @@ export default { fileExt ({ name }) { return getFileExtension(name, true) }, - fileSize ({ size }) { - return size ? `${size} bytes` : '' + fileSizeDisplay ({ size }) { + return size ? formatBytesDecimal(size) : '' + }, + getDownloadTooltipText ({ size }) { + return this.shouldPreviewImages + ? `${L('Download ({size})', { size: formatBytesDecimal(size) })}` + : L('Download') }, fileType ({ mimeType }) { return getFileType(mimeType) @@ -279,8 +285,14 @@ export default { .c-file-ext-and-size { display: flex; + align-items: flex-end; flex-direction: row; - column-gap: 0.25rem; + column-gap: 0.325rem; + } + + .c-file-size { + color: $text_1; + font-size: 0.8em; } } @@ -314,6 +326,8 @@ export default { .is-download-item { &:hover .c-attachment-actions-wrapper { display: flex; + flex-direction: column; + align-items: flex-end; } .c-preview-non-image { diff --git a/frontend/views/utils/filters.js b/frontend/views/utils/filters.js index f2642435d..4c2d57bb9 100644 --- a/frontend/views/utils/filters.js +++ b/frontend/views/utils/filters.js @@ -15,6 +15,17 @@ export const getFileType = ( return mimeType.match('image/') ? 'image' : 'non-image' } +export const formatBytesDecimal = (bytes: number, decimals: number = 2): string => { + if (bytes === 0) { return '0 Bytes' } + + const k = 1000 // Decimal base + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] + const i = Math.floor(Math.log(bytes) / Math.log(k)) + + const formattedValue = parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + return `${formattedValue} ${sizes[i]}` +} + /** * this function filters `list` by `keyword` * `list` should be an array of objects and strings