feat: Expo scaffold + auth screens + core screens (#39-#46, #48)
This commit is contained in:
55
components/Avatar.tsx
Normal file
55
components/Avatar.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import { View, Text, Image } from 'react-native';
|
||||
|
||||
interface AvatarProps {
|
||||
name?: string;
|
||||
uri?: string;
|
||||
size?: 'sm' | 'md' | 'lg' | 'xl';
|
||||
}
|
||||
|
||||
const sizeClasses = {
|
||||
sm: { container: 'w-8 h-8', text: 'text-xs' },
|
||||
md: { container: 'w-10 h-10', text: 'text-sm' },
|
||||
lg: { container: 'w-14 h-14', text: 'text-xl' },
|
||||
xl: { container: 'w-20 h-20', text: 'text-3xl' },
|
||||
};
|
||||
|
||||
const sizePx = { sm: 32, md: 40, lg: 56, xl: 80 };
|
||||
|
||||
function getInitials(name: string) {
|
||||
return name
|
||||
.split(' ')
|
||||
.slice(0, 2)
|
||||
.map((n) => n[0])
|
||||
.join('')
|
||||
.toUpperCase();
|
||||
}
|
||||
|
||||
function hashColor(name: string) {
|
||||
const colors = ['bg-blue-500', 'bg-purple-500', 'bg-green-500', 'bg-orange-500', 'bg-pink-500', 'bg-teal-500'];
|
||||
let hash = 0;
|
||||
for (const ch of name) hash = (hash * 31 + ch.charCodeAt(0)) & 0xffffffff;
|
||||
return colors[Math.abs(hash) % colors.length];
|
||||
}
|
||||
|
||||
export const Avatar: React.FC<AvatarProps> = ({ name = '', uri, size = 'md' }) => {
|
||||
const { container, text } = sizeClasses[size];
|
||||
const px = sizePx[size];
|
||||
|
||||
if (uri) {
|
||||
return (
|
||||
<Image
|
||||
source={{ uri }}
|
||||
className={`${container} rounded-full`}
|
||||
style={{ width: px, height: px, borderRadius: px / 2 }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View className={`${container} ${hashColor(name)} rounded-full items-center justify-center`}
|
||||
style={{ width: px, height: px, borderRadius: px / 2 }}>
|
||||
<Text className={`${text} font-bold text-white`}>{getInitials(name) || '?'}</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user