| import React, { useEffect } from 'react'; | |
| import { StyleSheet, Text, View } from 'react-native'; | |
| import Animated, { | |
| useSharedValue, | |
| useAnimatedStyle, | |
| withTiming, | |
| withDelay, | |
| interpolate, | |
| Easing, | |
| } from 'react-native-reanimated'; | |
| import { BlurView } from 'expo-blur'; | |
| import { COLORS } from '../constants/colors'; | |
| const AnimatedBlurView = Animated.createAnimatedComponent(BlurView); | |
| interface StatCardProps { | |
| label: string; | |
| value: string | number; | |
| icon?: string; | |
| delay?: number; | |
| color?: string; | |
| compact?: boolean; | |
| } | |
| export const StatCard: React.FC<StatCardProps> = ({ | |
| label, | |
| value, | |
| icon, | |
| delay = 0, | |
| color = COLORS.primary, | |
| compact = false, | |
| }) => { | |
| const progress = useSharedValue(0); | |
| useEffect(() => { | |
| progress.value = withDelay( | |
| delay, | |
| withTiming(1, { duration: 500, easing: Easing.out(Easing.cubic) }) | |
| ); | |
| }, []); | |
| const animStyle = useAnimatedStyle(() => ({ | |
| opacity: progress.value, | |
| transform: [ | |
| { translateY: interpolate(progress.value, [0, 1], [15, 0]) }, | |
| ], | |
| })); | |
| return ( | |
| <AnimatedBlurView tint="dark" intensity={40} style={[styles.container, compact && styles.compact, animStyle]}> | |
| {icon && <Text style={styles.icon}>{icon}</Text>} | |
| <Text style={[styles.value, { color }]}>{value}</Text> | |
| <Text style={styles.label}>{label}</Text> | |
| </AnimatedBlurView> | |
| ); | |
| }; | |
| const styles = StyleSheet.create({ | |
| container: { | |
| backgroundColor: 'transparent', | |
| borderRadius: 16, | |
| borderWidth: 1, | |
| borderColor: 'rgba(255,255,255,0.08)', | |
| padding: 14, | |
| alignItems: 'center', | |
| justifyContent: 'center', | |
| minWidth: 90, | |
| flex: 1, | |
| margin: 4, | |
| overflow: 'hidden', | |
| }, | |
| compact: { | |
| padding: 10, | |
| }, | |
| icon: { | |
| fontSize: 20, | |
| marginBottom: 4, | |
| }, | |
| value: { | |
| fontFamily: 'Outfit_900Black', | |
| fontSize: 22, | |
| marginBottom: 2, | |
| fontVariant: ['tabular-nums'], | |
| letterSpacing: 1, | |
| }, | |
| label: { | |
| fontFamily: 'Outfit_700Bold', | |
| fontSize: 9, | |
| color: COLORS.textDim, | |
| textTransform: 'uppercase', | |
| letterSpacing: 1.5, | |
| textAlign: 'center', | |
| }, | |
| }); | |