add support for identicon ring to avatar

This commit is contained in:
Pavel Prichodko 2022-06-13 16:18:06 +02:00
parent 47ea7a90ad
commit 29b0e23319
No known key found for this signature in database
GPG Key ID: 8E4C82D464215E83
3 changed files with 107 additions and 35 deletions

View File

@ -1,7 +1,8 @@
import React from 'react'
import React, { useMemo } from 'react'
import { Image } from '../image'
import { Base, Indicator, Initials } from './styles'
import { Base, Content, Indicator, Initials } from './styles'
import { generateIdenticonRing } from './utils'
import type { Variants } from './styles'
@ -11,46 +12,43 @@ interface Props {
indicator?: 'online' | 'offline'
src?: string
color?: string
colorHash?: number[][]
}
const Avatar = (props: Props) => {
const { size, name, src, color, indicator } = props
const { size, name, src, color, indicator, colorHash } = props
// const identicon = useMemo(() => {
// const colors = colorWheel
// .map((color, idx) => {
// const prevDeg = idx === 0 ? '0deg' : `${colorWheel[idx - 1][1]}deg`
// return `${color[0]} ${prevDeg} ${color[1]}deg`
// })
// .join(',')
// return `conic-gradient(${colors})`
// }, [colorWheel])
// const intials = useMemo(() => {
// if (contact && contact?.customName) {
// return contact.customName.slice(0, 2)
// }
// if (contact && contact.trueName) {
// return contact.trueName.slice(0, 2)
// }
// }, [contact])
const identiconRing = useMemo(() => {
if (colorHash) {
const gradient = generateIdenticonRing(colorHash)
return `conic-gradient(${gradient})`
}
}, [colorHash])
const initials = name ? name.slice(0, 1) : ''
return (
<Base size={size} style={{ backgroundColor: color }}>
{initials && <Initials size={size}>{initials}</Initials>}
{src && (
<Image
src={src}
alt="avatar"
width="100%"
height="100%"
fit="cover"
radius="full"
/>
)}
{indicator && <Indicator size={size} state={indicator} />}
<Base
size={size}
style={{
background: identiconRing,
padding: !identiconRing ? 0 : undefined,
}}
>
<Content style={{ background: color }}>
{initials && <Initials size={size}>{initials}</Initials>}
{src && (
<Image
src={src}
alt="avatar"
width="100%"
height="100%"
fit="cover"
radius="full"
/>
)}
{indicator && <Indicator size={size} state={indicator} />}
</Content>
</Base>
)
}

View File

@ -6,7 +6,6 @@ export type Variants = VariantProps<typeof Base>
export const Base = styled('div', {
position: 'relative',
background: '$primary-1',
borderRadius: '100%',
flexShrink: 0,
@ -15,39 +14,54 @@ export const Base = styled('div', {
20: {
width: 20,
height: 20,
padding: 1,
},
24: {
width: 24,
height: 24,
padding: 1,
},
32: {
width: 32,
height: 32,
padding: 2,
},
36: {
width: 36,
height: 36,
padding: 2,
},
44: {
width: 44,
height: 44,
padding: 2,
},
64: {
width: 64,
height: 64,
padding: 3,
},
80: {
width: 80,
height: 80,
padding: 4,
},
120: {
width: 120,
height: 120,
padding: 5,
},
},
},
})
export const Content = styled('div', {
background: '$primary-1',
borderRadius: '100%',
width: '100%',
height: '100%',
})
export const Indicator = styled('span', {
position: 'absolute',
right: -2,

View File

@ -0,0 +1,60 @@
/**
* returns value for conic-gradient
*/
export const generateIdenticonRing = (colorHash: number[][]) => {
const segments = colorHash.reduce((acc, segment) => (acc += segment[0]), 0)
let prevAngle = 0
const gradient = colorHash.reduce((acc, segment, index) => {
const [length, colorIndex] = segment
const color = COLORS[colorIndex]
const nextAngle = Math.round(prevAngle + (length * 360) / segments)
acc += `${color} ${prevAngle}deg ${nextAngle}deg`
if (index !== colorHash.length - 1) {
acc += `, `
}
prevAngle = nextAngle
return acc
}, '')
return gradient
}
const COLORS = [
'#000000',
'#726F6F',
'#C4C4C4',
'#E7E7E7',
'#FFFFFF',
'#00FF00',
'#009800',
'#B8FFBB',
'#FFC413',
'#9F5947',
'#FFFF00',
'#A8AC00',
'#FFFFB0',
'#FF5733',
'#FF0000',
'#9A0000',
'#FF9D9D',
'#FF0099',
'#C80078',
'#FF00FF',
'#900090',
'#FFB0FF',
'#9E00FF',
'#0000FF',
'#000086',
'#9B81FF',
'#3FAEF9',
'#9A6600',
'#00FFFF',
'#008694',
'#C2FFFF',
'#00F0B6',
]