63 lines
1.4 KiB
TypeScript
63 lines
1.4 KiB
TypeScript
import React, { useEffect } from 'react';
|
|
import { View, StyleSheet } from 'react-native';
|
|
import Animated, {
|
|
useAnimatedStyle,
|
|
useSharedValue,
|
|
withRepeat,
|
|
withTiming,
|
|
Easing,
|
|
} from 'react-native-reanimated';
|
|
import { LinearGradient } from 'expo-linear-gradient';
|
|
import { Colors, BorderRadius } from '@/constants/theme';
|
|
|
|
interface SkeletonLoaderProps {
|
|
width?: number | string;
|
|
height?: number;
|
|
borderRadius?: number;
|
|
style?: any;
|
|
}
|
|
|
|
export default function SkeletonLoader({
|
|
width = '100%',
|
|
height = 120,
|
|
borderRadius = BorderRadius.large,
|
|
style,
|
|
}: SkeletonLoaderProps) {
|
|
const translateX = useSharedValue(-300);
|
|
|
|
useEffect(() => {
|
|
translateX.value = withRepeat(
|
|
withTiming(300, { duration: 1200, easing: Easing.linear }),
|
|
-1
|
|
);
|
|
}, []);
|
|
|
|
const shimmerStyle = useAnimatedStyle(() => ({
|
|
transform: [{ translateX: translateX.value }],
|
|
}));
|
|
|
|
return (
|
|
<View
|
|
style={[
|
|
{
|
|
width: width as any,
|
|
height,
|
|
borderRadius,
|
|
backgroundColor: Colors.background.card,
|
|
overflow: 'hidden',
|
|
},
|
|
style,
|
|
]}
|
|
>
|
|
<Animated.View style={[StyleSheet.absoluteFill, shimmerStyle]}>
|
|
<LinearGradient
|
|
colors={['transparent', 'rgba(255,255,255,0.04)', 'transparent']}
|
|
start={{ x: 0, y: 0 }}
|
|
end={{ x: 1, y: 0 }}
|
|
style={StyleSheet.absoluteFill}
|
|
/>
|
|
</Animated.View>
|
|
</View>
|
|
);
|
|
}
|