From 6a7fe714475c854131028c1554c31b04e4c9f7cc Mon Sep 17 00:00:00 2001 From: Andrey Sobolev Date: Tue, 6 Jun 2023 14:33:32 +0700 Subject: [PATCH] UBER-373: Fix blurry avatars and other images (#3353) Signed-off-by: Andrey Sobolev --- .../text-editor/src/components/imageExt.ts | 23 ++++++++- packages/ui/src/types.ts | 21 +++++++++ .../src/components/AttachmentPresenter.svelte | 16 ++++++- .../src/components/AttachmentPreview.svelte | 12 ++++- .../src/components/Avatar.svelte | 10 ++-- plugins/contact-resources/src/index.ts | 47 +++++++++++++------ plugins/contact/src/index.ts | 2 +- plugins/contact/src/utils.ts | 8 +++- .../src/components/LoginApp.svelte | 2 +- server/front/src/index.ts | 19 ++++++++ 10 files changed, 133 insertions(+), 27 deletions(-) diff --git a/packages/text-editor/src/components/imageExt.ts b/packages/text-editor/src/components/imageExt.ts index 644c66824c..4830803c89 100644 --- a/packages/text-editor/src/components/imageExt.ts +++ b/packages/text-editor/src/components/imageExt.ts @@ -1,6 +1,6 @@ import { getEmbeddedLabel } from '@hcengineering/platform' import { getFileUrl } from '@hcengineering/presentation' -import { Action, Menu, getEventPositionElement, showPopup } from '@hcengineering/ui' +import { Action, IconSize, Menu, getEventPositionElement, getIconSize2x, showPopup } from '@hcengineering/ui' import { Node, createNodeFromContent, mergeAttributes, nodeInputRule } from '@tiptap/core' import { Plugin, PluginKey } from 'prosemirror-state' import plugin from '../plugin' @@ -88,6 +88,27 @@ export const ImageRef = Node.create({ HTMLAttributes ) merged.src = getFileUrl(merged['file-id'], 'full') + let width: IconSize | undefined + switch (merged.width) { + case '32px': + width = 'small' + break + case '64px': + width = 'medium' + break + case '128px': + case '256px': + width = 'large' + break + case '512px': + width = 'x-large' + break + } + if (width !== undefined) { + merged.src = getFileUrl(merged['file-id'], width) + merged.srcset = + getFileUrl(merged['file-id'], width) + ' 1x,' + getFileUrl(merged['file-id'], getIconSize2x(width)) + ' 2x' + } merged.class = 'textEditorImage' return ['img', merged] }, diff --git a/packages/ui/src/types.ts b/packages/ui/src/types.ts index 9f52e30ce1..92323d4647 100644 --- a/packages/ui/src/types.ts +++ b/packages/ui/src/types.ts @@ -189,6 +189,7 @@ export type TooltipAlignment = 'top' | 'bottom' | 'left' | 'right' export type VerticalAlignment = 'top' | 'bottom' export type HorizontalAlignment = 'left' | 'right' +// Be aware to update front getResizeID() to properly store resized images. export type IconSize = | 'inline' | 'tiny' @@ -202,6 +203,26 @@ export type IconSize = | '2x-large' | 'full' +export function getIconSize2x (size: IconSize): IconSize { + switch (size) { + case 'inline': + case 'tiny': + case 'x-small': + case 'small': + case 'card': + case 'smaller': + case 'medium': + return 'large' + case 'large': + return 'x-large' + case 'x-large': + return '2x-large' + case '2x-large': + case 'full': + return 'full' + } +} + export interface DateOrShift { date?: number shift?: number diff --git a/plugins/attachment-resources/src/components/AttachmentPresenter.svelte b/plugins/attachment-resources/src/components/AttachmentPresenter.svelte index 5a2ae23be5..83a962fa66 100644 --- a/plugins/attachment-resources/src/components/AttachmentPresenter.svelte +++ b/plugins/attachment-resources/src/components/AttachmentPresenter.svelte @@ -16,7 +16,7 @@
@@ -83,7 +95,7 @@ class="flex-center icon" class:svg={value.type === 'image/svg+xml'} class:image={isImage(value.type)} - style:background-image={isImage(value.type) ? `url(${getFileUrl(value.file, 'large')})` : 'none'} + style={imgStyle} > {#if !isImage(value.type)}{iconLabel(value.name)}{/if}
--> diff --git a/plugins/attachment-resources/src/components/AttachmentPreview.svelte b/plugins/attachment-resources/src/components/AttachmentPreview.svelte index 23c9822a28..9204b19efb 100644 --- a/plugins/attachment-resources/src/components/AttachmentPreview.svelte +++ b/plugins/attachment-resources/src/components/AttachmentPreview.svelte @@ -16,7 +16,7 @@
{#if url} {#if size === 'large' || size === 'x-large' || size === '2x-large'} - {''} + {''} {/if} - {''} + {''} {:else} {/if} diff --git a/plugins/contact-resources/src/index.ts b/plugins/contact-resources/src/index.ts index 4f158901e2..91e918ebfe 100644 --- a/plugins/contact-resources/src/index.ts +++ b/plugins/contact-resources/src/index.ts @@ -19,12 +19,22 @@ import { Class, Client, DocumentQuery, Ref, RelatedDocument, WithLookup } from ' import login from '@hcengineering/login' import { IntlString, Resources, getResource } from '@hcengineering/platform' import { MessageBox, ObjectSearchResult, getClient, getFileUrl } from '@hcengineering/presentation' -import { AnyComponent, AnySvelteComponent, TooltipAlignment, parseURL, showPopup } from '@hcengineering/ui' +import { + AnyComponent, + AnySvelteComponent, + IconSize, + TooltipAlignment, + getIconSize2x, + parseURL, + showPopup +} from '@hcengineering/ui' import AccountArrayEditor from './components/AccountArrayEditor.svelte' import AccountBox from './components/AccountBox.svelte' import AssigneeBox from './components/AssigneeBox.svelte' import Avatar from './components/Avatar.svelte' import ChannelFilter from './components/ChannelFilter.svelte' +import ChannelPanel from './components/ChannelPanel.svelte' +import ChannelPresenter from './components/ChannelPresenter.svelte' import Channels from './components/Channels.svelte' import ChannelsDropdown from './components/ChannelsDropdown.svelte' import ChannelsEditor from './components/ChannelsEditor.svelte' @@ -39,17 +49,21 @@ import ContactsTabs from './components/ContactsTabs.svelte' import CreateEmployee from './components/CreateEmployee.svelte' import CreateOrganization from './components/CreateOrganization.svelte' import CreatePerson from './components/CreatePerson.svelte' +import DeleteConfirmationPopup from './components/DeleteConfirmationPopup.svelte' import EditEmployee from './components/EditEmployee.svelte' import EditMember from './components/EditMember.svelte' import EditOrganization from './components/EditOrganization.svelte' import EditPerson from './components/EditPerson.svelte' import EditableAvatar from './components/EditableAvatar.svelte' +import EmployeeAccountFilterValuePresenter from './components/EmployeeAccountFilterValuePresenter.svelte' import EmployeeAccountPresenter from './components/EmployeeAccountPresenter.svelte' import EmployeeAccountRefPresenter from './components/EmployeeAccountRefPresenter.svelte' import EmployeeArrayEditor from './components/EmployeeArrayEditor.svelte' import EmployeeBox from './components/EmployeeBox.svelte' import EmployeeBrowser from './components/EmployeeBrowser.svelte' import EmployeeEditor from './components/EmployeeEditor.svelte' +import EmployeeFilter from './components/EmployeeFilter.svelte' +import EmployeeFilterValuePresenter from './components/EmployeeFilterValuePresenter.svelte' import EmployeePresenter from './components/EmployeePresenter.svelte' import EmployeeRefPresenter from './components/EmployeeRefPresenter.svelte' import MemberPresenter from './components/MemberPresenter.svelte' @@ -61,24 +75,18 @@ import OrganizationPresenter from './components/OrganizationPresenter.svelte' import PersonEditor from './components/PersonEditor.svelte' import PersonPresenter from './components/PersonPresenter.svelte' import PersonRefPresenter from './components/PersonRefPresenter.svelte' +import SelectAvatars from './components/SelectAvatars.svelte' import SocialEditor from './components/SocialEditor.svelte' import SpaceMembers from './components/SpaceMembers.svelte' import UserBox from './components/UserBox.svelte' +import UserBoxItems from './components/UserBoxItems.svelte' import UserBoxList from './components/UserBoxList.svelte' import UserInfo from './components/UserInfo.svelte' import UsersPopup from './components/UsersPopup.svelte' import ActivityChannelMessage from './components/activity/ActivityChannelMessage.svelte' +import ActivityChannelPresenter from './components/activity/ActivityChannelPresenter.svelte' import ExpandRightDouble from './components/icons/ExpandRightDouble.svelte' import IconMembers from './components/icons/Members.svelte' -import ChannelPresenter from './components/ChannelPresenter.svelte' -import ChannelPanel from './components/ChannelPanel.svelte' -import ActivityChannelPresenter from './components/activity/ActivityChannelPresenter.svelte' -import SelectAvatars from './components/SelectAvatars.svelte' -import UserBoxItems from './components/UserBoxItems.svelte' -import EmployeeFilter from './components/EmployeeFilter.svelte' -import EmployeeFilterValuePresenter from './components/EmployeeFilterValuePresenter.svelte' -import EmployeeAccountFilterValuePresenter from './components/EmployeeAccountFilterValuePresenter.svelte' -import DeleteConfirmationPopup from './components/DeleteConfirmationPopup.svelte' import contact from './plugin' import { @@ -98,6 +106,7 @@ import { resolveLocation } from './utils' +export * from './utils' export { employeeByIdStore, employeesStore } from './utils' export { Channels, @@ -254,8 +263,6 @@ export interface PersonLabelTooltip { props?: any } -export * from './utils' - export default async (): Promise => ({ actionImpl: { KickEmployee: kickEmployee, @@ -321,9 +328,19 @@ export default async (): Promise => ({ ) => await queryContact(contact.class.Organization, client, query, filter) }, function: { - GetFileUrl: getFileUrl, - GetGravatarUrl: getGravatarUrl, - GetColorUrl: (uri: string) => uri, + GetFileUrl: (file: string, size: IconSize, fileName?: string) => { + return [ + getFileUrl(file, size, fileName), + getFileUrl(file, size, fileName) + ' 1x', + getFileUrl(file, getIconSize2x(size), fileName) + ' 2x' + ] + }, + GetGravatarUrl: (file: string, size: IconSize, fileName?: string) => [ + getGravatarUrl(file, size), + getGravatarUrl(file, size) + ' 1x', + getGravatarUrl(file, getIconSize2x(size)) + ' 2x' + ], + GetColorUrl: (uri: string) => [uri], EmployeeSort: employeeSort, FilterChannelInResult: filterChannelInResult, FilterChannelNinResult: filterChannelNinResult, diff --git a/plugins/contact/src/index.ts b/plugins/contact/src/index.ts index 3740537265..653de10797 100644 --- a/plugins/contact/src/index.ts +++ b/plugins/contact/src/index.ts @@ -81,7 +81,7 @@ export enum AvatarType { /** * @public */ -export type GetAvatarUrl = (uri: string, size: IconSize) => string +export type GetAvatarUrl = (uri: string, size: IconSize) => string[] /** * @public diff --git a/plugins/contact/src/utils.ts b/plugins/contact/src/utils.ts index 2599f7b035..82cfcaee3e 100644 --- a/plugins/contact/src/utils.ts +++ b/plugins/contact/src/utils.ts @@ -54,7 +54,7 @@ export function getGravatarUrl ( case 'x-small': case 'small': case 'medium': - width = 64 + width = 128 break case 'large': width = 256 @@ -62,6 +62,12 @@ export function getGravatarUrl ( case 'x-large': width = 512 break + case '2x-large': + width = 1024 + break + case 'full': + width = 2048 + break } return `https://gravatar.com/avatar/${gravatarId}?s=${width}&d=${placeholder}` } diff --git a/plugins/login-resources/src/components/LoginApp.svelte b/plugins/login-resources/src/components/LoginApp.svelte index 6010d6b917..e342f28495 100644 --- a/plugins/login-resources/src/components/LoginApp.svelte +++ b/plugins/login-resources/src/components/LoginApp.svelte @@ -101,7 +101,7 @@ } } .back { - // background: url('../../img/back_signin.png'); + background-image: url('../../img/login_back.png'); background-image: -webkit-image-set( '../../img/login_back.avif' 1x, '../../img/login_back_2x.avif' 2x, diff --git a/server/front/src/index.ts b/server/front/src/index.ts index b733bc8c93..b695bcf4c7 100644 --- a/server/front/src/index.ts +++ b/server/front/src/index.ts @@ -491,6 +491,19 @@ export function start ( server.close() } } + +// export type IconSize = +// | 'inline' +// | 'tiny' +// | 'card' +// | 'x-small' +// | 'smaller' +// | 'small' +// | 'medium' +// | 'large' +// | 'x-large' +// | '2x-large' +// | 'full' async function getResizeID ( size: string, uuid: string, @@ -502,7 +515,9 @@ async function getResizeID ( switch (size) { case 'inline': case 'tiny': + case 'card': case 'x-small': + case 'smaller': case 'small': case 'medium': width = 64 @@ -513,6 +528,10 @@ async function getResizeID ( case 'x-large': width = 512 break + case '2x-large': + size = '2x-large_v2' + width = 1024 + break } let hasSmall = false const sizeId = uuid + `%size%${width}`