94 lines
2.0 KiB
TypeScript
94 lines
2.0 KiB
TypeScript
import { View, Text, Image, ViewStyle, ImageStyle } from 'react-native'
|
|
|
|
const AVATAR_PALETTES = [
|
|
{ bg: '#003B7E', text: '#FFFFFF' },
|
|
{ bg: '#1D4ED8', text: '#FFFFFF' },
|
|
{ bg: '#059669', text: '#FFFFFF' },
|
|
{ bg: '#4338CA', text: '#FFFFFF' },
|
|
{ bg: '#B45309', text: '#FFFFFF' },
|
|
{ bg: '#0F766E', text: '#FFFFFF' },
|
|
]
|
|
|
|
function getInitials(name: string): string {
|
|
return name
|
|
.split(' ')
|
|
.slice(0, 2)
|
|
.map((w) => w[0]?.toUpperCase() ?? '')
|
|
.join('')
|
|
}
|
|
|
|
function getPalette(name: string) {
|
|
const index = name.charCodeAt(0) % AVATAR_PALETTES.length
|
|
return AVATAR_PALETTES[index]
|
|
}
|
|
|
|
interface AvatarProps {
|
|
name: string
|
|
imageUrl?: string
|
|
size?: number
|
|
shadow?: boolean
|
|
}
|
|
|
|
export function Avatar({ name, imageUrl, size = 48, shadow = false }: AvatarProps) {
|
|
const initials = getInitials(name)
|
|
const palette = getPalette(name)
|
|
|
|
const viewShadowStyle: ViewStyle = shadow
|
|
? {
|
|
shadowColor: '#000',
|
|
shadowOffset: { width: 0, height: 2 },
|
|
shadowOpacity: 0.12,
|
|
shadowRadius: 8,
|
|
elevation: 3,
|
|
}
|
|
: {}
|
|
|
|
const imageShadowStyle: ImageStyle = shadow
|
|
? {
|
|
shadowColor: '#000',
|
|
shadowOffset: { width: 0, height: 2 },
|
|
shadowOpacity: 0.12,
|
|
shadowRadius: 8,
|
|
}
|
|
: {}
|
|
|
|
if (imageUrl) {
|
|
return (
|
|
<Image
|
|
source={{ uri: imageUrl }}
|
|
style={[
|
|
{ width: size, height: size, borderRadius: size / 2 },
|
|
imageShadowStyle,
|
|
]}
|
|
/>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<View
|
|
style={[
|
|
{
|
|
width: size,
|
|
height: size,
|
|
borderRadius: size / 2,
|
|
backgroundColor: palette.bg,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
},
|
|
viewShadowStyle,
|
|
]}
|
|
>
|
|
<Text
|
|
style={{
|
|
color: palette.text,
|
|
fontSize: size * 0.36,
|
|
fontWeight: '700',
|
|
letterSpacing: 0.5,
|
|
}}
|
|
>
|
|
{initials}
|
|
</Text>
|
|
</View>
|
|
)
|
|
}
|