UBER-486: replaced avatar colors (#3724)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2023-09-21 07:07:53 +03:00 committed by GitHub
parent a07f88033f
commit 07bcffe363
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 79 additions and 37 deletions

View File

@ -50,11 +50,13 @@ const defineAvatarColor = (
dark: boolean = false dark: boolean = false
): ColorDefinition => { ): ColorDefinition => {
const background = rgbToHex(hslToRgb(h / 360, s / 100, l / 100)) const background = rgbToHex(hslToRgb(h / 360, s / 100, l / 100))
const icon = rgbToHex(hslToRgb(h / 360, 0.5, 0.6))
const title = rgbToHex(hslToRgb(h / 360, 0.9, 0.9))
return { return {
name, name,
color: background, color: background,
icon: undefined, icon,
title: undefined, title,
number: undefined, number: undefined,
background: background:
gradient.length === 1 gradient.length === 1
@ -264,6 +266,21 @@ export function getPlatformAvatarColorForTextDef (text: string, darkTheme: boole
return getPlatformAvatarColorDef(hashCode(text), darkTheme) return getPlatformAvatarColorDef(hashCode(text), darkTheme)
} }
/**
* @public
*/
export function getPlatformAvatarColorByName (name: string, darkTheme: boolean): ColorDefinition {
const palette = darkTheme ? avatarDarkColors : avatarWhiteColors
return palette.find((col) => col.name === name) ?? palette[0]
}
/**
* @public
*/
export function getPlatformAvatarColors (darkTheme: boolean): readonly ColorDefinition[] {
return darkTheme ? avatarDarkColors : avatarWhiteColors
}
/** /**
* @public * @public
*/ */

View File

@ -27,17 +27,19 @@
</script> </script>
<script lang="ts"> <script lang="ts">
import contact, { import contact, { AvatarProvider, AvatarType, getFirstName, getLastName } from '@hcengineering/contact'
AvatarProvider,
AvatarType,
getAvatarColorForId,
getFirstName,
getLastName
} from '@hcengineering/contact'
import { Client, Ref } from '@hcengineering/core' import { Client, Ref } from '@hcengineering/core'
import { Asset, getResource } from '@hcengineering/platform' import { Asset, getResource } from '@hcengineering/platform'
import { getBlobURL, getClient } from '@hcengineering/presentation' import { getBlobURL, getClient } from '@hcengineering/presentation'
import { AnySvelteComponent, Icon, IconSize } from '@hcengineering/ui' import {
AnySvelteComponent,
Icon,
IconSize,
getPlatformAvatarColorForTextDef,
getPlatformAvatarColorByName,
themeStore,
ColorDefinition
} from '@hcengineering/ui'
import { getAvatarProviderId } from '../utils' import { getAvatarProviderId } from '../utils'
import AvatarIcon from './icons/Avatar.svelte' import AvatarIcon from './icons/Avatar.svelte'
@ -49,7 +51,7 @@
let url: string[] | undefined let url: string[] | undefined
let avatarProvider: AvatarProvider | undefined let avatarProvider: AvatarProvider | undefined
let color: string | undefined = undefined let color: ColorDefinition | undefined = undefined
$: fname = getFirstName(name ?? '') $: fname = getFirstName(name ?? '')
$: lname = getLastName(name ?? '') $: lname = getLastName(name ?? '')
@ -68,7 +70,7 @@
if (!avatarProvider || avatarProvider.type === AvatarType.COLOR) { if (!avatarProvider || avatarProvider.type === AvatarType.COLOR) {
url = undefined url = undefined
color = avatar.split('://')[1] color = getPlatformAvatarColorByName(avatar.split('://')[1], $themeStore.dark)
} else if (avatarProvider?.type === AvatarType.IMAGE) { } else if (avatarProvider?.type === AvatarType.IMAGE) {
url = (await getResource(avatarProvider.getUrl))(avatar, size) url = (await getResource(avatarProvider.getUrl))(avatar, size)
} else { } else {
@ -76,7 +78,7 @@
url = (await getResource(avatarProvider.getUrl))(uri, size) url = (await getResource(avatarProvider.getUrl))(uri, size)
} }
} else if (name != null) { } else if (name != null) {
color = getAvatarColorForId(name) color = getPlatformAvatarColorForTextDef(name, $themeStore.dark)
url = undefined url = undefined
avatarProvider = undefined avatarProvider = undefined
} else { } else {
@ -95,7 +97,7 @@
class="ava-{size} flex-center avatar-container" class="ava-{size} flex-center avatar-container"
class:no-img={!url && color} class:no-img={!url && color}
class:bordered={!url && color === undefined} class:bordered={!url && color === undefined}
style:background-color={url ? 'var(--theme-button-default)' : color} style:background-color={color && !url ? color.icon : 'var(--theme-button-default)'}
> >
{#if url} {#if url}
{#if size === 'large' || size === 'x-large' || size === '2x-large'} {#if size === 'large' || size === 'x-large' || size === '2x-large'}
@ -103,7 +105,11 @@
{/if} {/if}
<img class="ava-{size} ava-mask" src={url[0]} {srcset} alt={''} bind:this={imageElement} /> <img class="ava-{size} ava-mask" src={url[0]} {srcset} alt={''} bind:this={imageElement} />
{:else if name && displayName && displayName !== ''} {:else if name && displayName && displayName !== ''}
<div class="ava-text" data-name={displayName.toLocaleUpperCase()} /> <div
class="ava-text"
style:color={color ? color.title : 'var(--accented-button-color)'}
data-name={displayName.toLocaleUpperCase()}
/>
{:else} {:else}
<div class="icon"> <div class="icon">
<Icon icon={icon ?? AvatarIcon} size={'full'} /> <Icon icon={icon ?? AvatarIcon} size={'full'} />

View File

@ -15,8 +15,14 @@
<script lang="ts"> <script lang="ts">
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import attachment from '@hcengineering/attachment' import attachment from '@hcengineering/attachment'
import { AnySvelteComponent, IconSize, showPopup } from '@hcengineering/ui' import {
import { AvatarType, getAvatarColorForId } from '@hcengineering/contact' AnySvelteComponent,
IconSize,
showPopup,
getPlatformAvatarColorForTextDef,
themeStore
} from '@hcengineering/ui'
import { AvatarType } from '@hcengineering/contact'
import { Asset, getResource } from '@hcengineering/platform' import { Asset, getResource } from '@hcengineering/platform'
import AvatarComponent from './Avatar.svelte' import AvatarComponent from './Avatar.svelte'
@ -41,7 +47,7 @@
: AvatarType.IMAGE : AvatarType.IMAGE
$: selectedAvatar = selectedAvatarType === AvatarType.IMAGE ? avatar : uri $: selectedAvatar = selectedAvatarType === AvatarType.IMAGE ? avatar : uri
$: if (selectedAvatar === undefined && selectedAvatarType === AvatarType.COLOR) { $: if (selectedAvatar === undefined && selectedAvatarType === AvatarType.COLOR) {
selectedAvatar = getAvatarColorForId(name) selectedAvatar = getPlatformAvatarColorForTextDef(name ?? '', $themeStore.dark).name
} }
export async function createAvatar (): Promise<string | undefined> { export async function createAvatar (): Promise<string | undefined> {

View File

@ -15,16 +15,20 @@
<script lang="ts"> <script lang="ts">
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import { import { AvatarType, buildGravatarId, checkHasGravatar } from '@hcengineering/contact'
AvatarType,
buildGravatarId,
checkHasGravatar,
getAvatarColorForId,
getAvatarColors,
getAvatarColorName
} from '@hcengineering/contact'
import { Asset } from '@hcengineering/platform' import { Asset } from '@hcengineering/platform'
import { AnySvelteComponent, Label, showPopup, TabList, eventToHTMLElement } from '@hcengineering/ui' import {
AnySvelteComponent,
Label,
showPopup,
TabList,
eventToHTMLElement,
getPlatformAvatarColorForTextDef,
getPlatformAvatarColorByName,
getPlatformAvatarColors,
ColorDefinition,
themeStore
} from '@hcengineering/ui'
import { ColorsPopup } from '@hcengineering/view-resources' import { ColorsPopup } from '@hcengineering/view-resources'
import presentation, { Card, getFileUrl } from '@hcengineering/presentation' import presentation, { Card, getFileUrl } from '@hcengineering/presentation'
import contact from '../plugin' import contact from '../plugin'
@ -40,8 +44,9 @@
export let onSubmit: (avatarType?: AvatarType, avatar?: string, file?: Blob) => void export let onSubmit: (avatarType?: AvatarType, avatar?: string, file?: Blob) => void
const [schema, uri] = avatar?.split('://') || [] const [schema, uri] = avatar?.split('://') || []
const colors = getAvatarColors() const colors = getPlatformAvatarColors($themeStore.dark)
let color: string | undefined = (schema as AvatarType) === AvatarType.COLOR ? uri : undefined let color: ColorDefinition | undefined =
(schema as AvatarType) === AvatarType.COLOR ? getPlatformAvatarColorByName(uri, $themeStore.dark) : undefined
const initialSelectedType = (() => { const initialSelectedType = (() => {
if (file) { if (file) {
@ -56,7 +61,7 @@
const initialSelectedAvatar = (() => { const initialSelectedAvatar = (() => {
if (!avatar) { if (!avatar) {
return getAvatarColorForId(name) return getPlatformAvatarColorForTextDef(name ?? '', $themeStore.dark).name
} }
return avatar.includes('://') ? uri : avatar return avatar.includes('://') ? uri : avatar
@ -96,7 +101,7 @@
inputRef.click() inputRef.click()
} }
} else { } else {
selectedAvatar = color ?? getAvatarColorForId(name) selectedAvatar = color ? color.name : getPlatformAvatarColorForTextDef(name ?? '', $themeStore.dark).name
} }
} }
@ -119,13 +124,13 @@
if (blob === undefined) { if (blob === undefined) {
if (!selectedFile && (!avatar || avatar.includes('://'))) { if (!selectedFile && (!avatar || avatar.includes('://'))) {
selectedAvatarType = AvatarType.COLOR selectedAvatarType = AvatarType.COLOR
selectedAvatar = getAvatarColorForId(name) selectedAvatar = getPlatformAvatarColorForTextDef(name ?? '', $themeStore.dark).name
} }
return return
} }
if (blob === null) { if (blob === null) {
selectedAvatarType = AvatarType.COLOR selectedAvatarType = AvatarType.COLOR
selectedAvatar = getAvatarColorForId(name) selectedAvatar = getPlatformAvatarColorForTextDef(name ?? '', $themeStore.dark).name
selectedFile = undefined selectedFile = undefined
} else { } else {
selectedFile = blob selectedFile = blob
@ -151,7 +156,7 @@
if (!inputRef.value.length) { if (!inputRef.value.length) {
if (!selectedFile) { if (!selectedFile) {
selectedAvatarType = AvatarType.COLOR selectedAvatarType = AvatarType.COLOR
selectedAvatar = getAvatarColorForId(name) selectedAvatar = getPlatformAvatarColorForTextDef(name ?? '', $themeStore.dark).name
} }
} }
} }
@ -159,11 +164,17 @@
const showColorPopup = (event: MouseEvent) => { const showColorPopup = (event: MouseEvent) => {
showPopup( showPopup(
ColorsPopup, ColorsPopup,
{ colors, columns: 6, selected: getAvatarColorName(selectedAvatar) }, {
colors,
columns: 6,
selected: getPlatformAvatarColorByName(selectedAvatar, $themeStore.dark),
key: 'icon'
},
eventToHTMLElement(event), eventToHTMLElement(event),
(col) => { (col) => {
if (col != null) { if (col != null) {
color = selectedAvatar = colors[col].color color = colors[col]
selectedAvatar = color.name
} }
} }
) )

View File

@ -22,6 +22,7 @@
export let colors: readonly ColorDefinition[] = getPlatformColors($themeStore.dark) export let colors: readonly ColorDefinition[] = getPlatformColors($themeStore.dark)
export let columns: number = 8 export let columns: number = 8
export let selected: string | undefined = undefined export let selected: string | undefined = undefined
export let key: 'color' | 'icon' = 'color'
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
</script> </script>
@ -29,11 +30,12 @@
<PopupDialog label={view.string.ChooseAColor}> <PopupDialog label={view.string.ChooseAColor}>
<div class="color-grid" style="grid-template-columns: repeat({columns}, 1.5rem)"> <div class="color-grid" style="grid-template-columns: repeat({columns}, 1.5rem)">
{#each colors as color, i} {#each colors as color, i}
{@const col = key === 'color' ? color.color : color.icon}
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<div <div
class="color" class="color"
class:selected={selected === color.name} class:selected={selected === color.name}
style="background-color: {color.color}" style="background-color: {col}"
on:click={() => { on:click={() => {
dispatch('close', i) dispatch('close', i)
}} }}