UBERF-5595: set up attachments sizes (#4746)

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
Kristina
2024-02-24 00:03:59 +07:00
committed by GitHub
parent 0349cec3a2
commit 3e782658c6
23 changed files with 485 additions and 131 deletions
@@ -19,9 +19,11 @@
import attachment from '../plugin'
import AttachmentList from './AttachmentList.svelte'
import { AttachmentImageSize } from '../types'
export let value: Doc & { attachments?: number }
export let attachments: Attachment[] | undefined = undefined
export let imageSize: AttachmentImageSize = 'auto'
const query = createQuery()
const savedAttachmentsQuery = createQuery()
@@ -57,4 +59,4 @@
})
</script>
<AttachmentList attachments={resAttachments} {savedAttachmentsIds} />
<AttachmentList attachments={resAttachments} {savedAttachmentsIds} {imageSize} />
@@ -0,0 +1,128 @@
<!--
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { getIconSize2x, IconSize } from '@hcengineering/ui'
import { getFileUrl } from '@hcengineering/presentation'
import type { Attachment } from '@hcengineering/attachment'
import { AttachmentImageSize } from '../types'
export let value: Attachment
export let size: AttachmentImageSize = 'auto'
interface Dimensions {
width: 'auto' | number
height: 'auto' | number
}
const minSizeRem = 4
const maxSizeRem = 20
const preferredWidthMap = {
'x-large': 300
} as const
let dimensions: Dimensions
let urlSize: IconSize
$: dimensions = getDimensions(value, size)
$: urlSize = getUrlSize(size)
function getDimensions (value: Attachment, size: AttachmentImageSize): Dimensions {
if (size === 'auto') {
return {
width: 'auto',
height: 'auto'
}
}
const preferredWidth = preferredWidthMap[size]
const { metadata } = value
if (!metadata) {
return {
width: preferredWidth,
height: preferredWidth
}
}
const { originalWidth, originalHeight } = metadata
const maxSize = maxSizeRem * parseFloat(getComputedStyle(document.documentElement).fontSize)
const width = Math.min(originalWidth, preferredWidth)
const ratio = originalHeight / originalWidth
const height = width * ratio
if (height > maxSize) {
return {
width: maxSize / ratio,
height: maxSize
}
}
return {
width,
height
}
}
function getObjectFit (size: Dimensions): 'contain' | 'cover' {
if (size.width === 'auto' || size.height === 'auto') {
return 'contain'
}
const minSize = minSizeRem * parseFloat(getComputedStyle(document.documentElement).fontSize)
if (size.width < minSize || size.height < minSize) {
return 'cover'
}
return 'contain'
}
function getUrlSize (size: AttachmentImageSize): IconSize {
if (size === 'auto') {
return 'large'
}
return 'x-large'
}
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<img
src={getFileUrl(value.file, urlSize)}
style:object-fit={getObjectFit(dimensions)}
width={dimensions.width}
height={dimensions.height}
srcset={`${getFileUrl(value.file, urlSize, value.name)} 1x, ${getFileUrl(
value.file,
getIconSize2x(urlSize),
value.name
)} 2x`}
alt={value.name}
/>
<style lang="scss">
img {
max-width: 20rem;
max-height: 20rem;
border-radius: 0.75rem;
object-fit: contain;
min-height: 4rem;
min-width: 4rem;
}
</style>
@@ -16,16 +16,23 @@
import { Attachment } from '@hcengineering/attachment'
import { Ref } from '@hcengineering/core'
import { Scroller } from '@hcengineering/ui'
import AttachmentPreview from './AttachmentPreview.svelte'
import { AttachmentImageSize } from '../types'
export let attachments: Attachment[] = []
export let savedAttachmentsIds: Ref<Attachment>[] = []
export let imageSize: AttachmentImageSize | undefined = undefined
</script>
{#if attachments.length}
<Scroller contentDirection={'horizontal'} horizontal gap={'gap-3'}>
{#each attachments as attachment}
<AttachmentPreview value={attachment} isSaved={savedAttachmentsIds?.includes(attachment._id) ?? false} />
<AttachmentPreview
value={attachment}
isSaved={savedAttachmentsIds?.includes(attachment._id) ?? false}
{imageSize}
/>
{/each}
</Scroller>
{/if}
@@ -18,9 +18,11 @@
import { Attachment } from '@hcengineering/attachment'
import { createQuery, getClient } from '@hcengineering/presentation'
import { ActionIcon, IconAdd, Label, Loading } from '@hcengineering/ui'
import { setPlatformStatus, unknownError } from '@hcengineering/platform'
import { AttachmentPresenter } from '..'
import attachment from '../plugin'
import { uploadFile } from '../utils'
import { getAttachmentMetadata, uploadFile } from '../utils'
// export let attachments: number
export let object: Doc
@@ -51,14 +53,21 @@
}
async function createAttachment (file: File) {
const uuid = await uploadFile(file)
await client.addCollection(attachment.class.Attachment, object.space, object._id, object._class, 'attachments', {
name: file.name,
file: uuid,
type: file.type,
size: file.size,
lastModified: file.lastModified
})
try {
const uuid = await uploadFile(file)
const metadata = await getAttachmentMetadata(file, uuid)
await client.addCollection(attachment.class.Attachment, object.space, object._id, object._class, 'attachments', {
name: file.name,
file: uuid,
type: file.type,
size: file.size,
lastModified: file.lastModified,
metadata
})
} catch (e) {
void setPlatformStatus(unknownError(e))
}
}
async function fileSelected (): Promise<void> {
@@ -15,19 +15,25 @@
-->
<script lang="ts">
import type { Attachment } from '@hcengineering/attachment'
import { getFileUrl, PDFViewer } from '@hcengineering/presentation'
import { showPopup, closeTooltip, getIconSize2x } from '@hcengineering/ui'
import { PDFViewer } from '@hcengineering/presentation'
import { showPopup, closeTooltip } from '@hcengineering/ui'
import { ListSelectionProvider } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte'
import { getType } from '../utils'
import AttachmentPresenter from './AttachmentPresenter.svelte'
import AttachmentActions from './AttachmentActions.svelte'
import AudioPlayer from './AudioPlayer.svelte'
import { ListSelectionProvider } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte'
import { AttachmentImageSize } from '../types'
import AttachmentImagePreview from './AttachmentImagePreview.svelte'
import AttachmentVideoPreview from './AttachmentVideoPreview.svelte'
export let value: Attachment
export let isSaved: boolean = false
export let listProvider: ListSelectionProvider | undefined = undefined
export let imageSize: AttachmentImageSize = 'auto'
export let removable: boolean = false
const dispatch = createEventDispatcher()
$: type = getType(value.type)
@@ -49,15 +55,7 @@
dispatch('open', popupInfo.id)
}}
>
<img
src={getFileUrl(value.file, 'large')}
srcset={`${getFileUrl(value.file, 'large', value.name)} 1x, ${getFileUrl(
value.file,
getIconSize2x('large'),
value.name
)} 2x`}
alt={value.name}
/>
<AttachmentImagePreview {value} size={imageSize} />
<div class="actions conner">
<AttachmentActions attachment={value} {isSaved} {removable} />
</div>
@@ -71,13 +69,7 @@
</div>
{:else if type === 'video'}
<div class="content buttonContainer flex-center">
<video controls>
<source src={getFileUrl(value.file, 'full', value.name)} />
<track kind="captions" label={value.name} />
<div class="container">
<AttachmentPresenter {value} />
</div>
</video>
<AttachmentVideoPreview {value} />
<div class="actions conner">
<AttachmentActions attachment={value} {isSaved} {removable} />
</div>
@@ -129,17 +121,5 @@
.content {
max-width: 20rem;
max-height: 20rem;
img,
video {
max-width: 20rem;
max-height: 20rem;
border-radius: 0.75rem;
width: auto;
height: auto;
}
img {
object-fit: contain;
}
}
</style>
@@ -17,10 +17,17 @@
import { Attachment } from '@hcengineering/attachment'
import { Account, Class, Doc, generateId, IdMap, Ref, Space, toIdMap } from '@hcengineering/core'
import { IntlString, setPlatformStatus, unknownError, Asset } from '@hcengineering/platform'
import { createQuery, DraftController, draftsStore, getClient } from '@hcengineering/presentation'
import {
createQuery,
DraftController,
draftsStore,
getClient,
getFileUrl,
getImageSize
} from '@hcengineering/presentation'
import textEditor, { AttachIcon, type RefAction, ReferenceInput } from '@hcengineering/text-editor'
import { Loading, type AnySvelteComponent } from '@hcengineering/ui'
import { deleteFile, uploadFile } from '../utils'
import { deleteFile, getAttachmentMetadata, uploadFile } from '../utils'
import attachment from '../plugin'
import AttachmentPresenter from './AttachmentPresenter.svelte'
@@ -103,6 +110,8 @@
async function createAttachment (file: File) {
try {
const uuid = await uploadFile(file)
const metadata = await getAttachmentMetadata(file, uuid)
const _id: Ref<Attachment> = generateId()
attachments.set(_id, {
_id,
@@ -117,7 +126,8 @@
file: uuid,
type: file.type,
size: file.size,
lastModified: file.lastModified
lastModified: file.lastModified,
metadata
})
newAttachments.add(_id)
attachments = attachments
@@ -20,8 +20,9 @@
import { createQuery, DraftController, draftsStore, getClient } from '@hcengineering/presentation'
import textEditor, { AttachIcon, type RefAction, StyledTextBox } from '@hcengineering/text-editor'
import { ButtonSize } from '@hcengineering/ui'
import attachment from '../plugin'
import { deleteFile, uploadFile } from '../utils'
import { deleteFile, getAttachmentMetadata, uploadFile } from '../utils'
import AttachmentsGrid from './AttachmentsGrid.svelte'
export let objectId: Ref<Doc> | undefined = undefined
@@ -133,7 +134,9 @@
if (space === undefined || objectId === undefined || _class === undefined) return
try {
const uuid = await uploadFile(file)
const metadata = await getAttachmentMetadata(file, uuid)
const _id: Ref<Attachment> = generateId()
attachments.set(_id, {
_id,
_class: attachment.class.Attachment,
@@ -147,7 +150,8 @@
file: uuid,
type: file.type,
size: file.size,
lastModified: file.lastModified
lastModified: file.lastModified,
metadata
})
newAttachments.add(_id)
attachments = attachments
@@ -0,0 +1,74 @@
<!--
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { getFileUrl } from '@hcengineering/presentation'
import type { Attachment } from '@hcengineering/attachment'
import AttachmentPresenter from './AttachmentPresenter.svelte'
export let value: Attachment
const maxSizeRem = 20
const baseSizeRem = 12
const minSizeRem = 4
$: dimensions = getDimensions(value)
function getDimensions (value: Attachment): { width: number, height: number } {
const fontSize = parseFloat(getComputedStyle(document.documentElement).fontSize)
if (!value.metadata) {
const baseSize = baseSizeRem * fontSize
return { width: baseSize, height: baseSize }
}
const { originalWidth, originalHeight } = value.metadata
const maxSize = maxSizeRem * fontSize
// For mp4 audio files, we don't have originalWidth, originalHeight
if (originalWidth === 0 || originalHeight === 0) {
return { width: maxSize, height: minSizeRem * fontSize }
}
const ratio = originalHeight / originalWidth
const width = Math.min(maxSize, originalWidth)
const height = width * ratio
if (height > maxSize) {
return { width: maxSize / ratio, height: maxSize }
}
return { width, height }
}
</script>
<video controls width={dimensions.width} height={dimensions.height}>
<source src={getFileUrl(value.file, 'full', value.name)} />
<track kind="captions" label={value.name} />
<div class="container">
<AttachmentPresenter {value} />
</div>
</video>
<style lang="scss">
video {
max-width: 20rem;
max-height: 20rem;
min-width: 4rem;
min-height: 4rem;
border-radius: 0.75rem;
}
</style>