File size: 2,059 Bytes
bb8f662
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import React, { useEffect, useRef } from 'react';
import { View, Animated, StyleSheet } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
import { theme } from '../styles/theme';
export default function SkeletonLoader({ 
  variant = 'text', 
  width = '100%', 
  height = 20,
  style 
}) {
  const animatedValue = useRef(new Animated.Value(0)).current;
  useEffect(() => {
    Animated.loop(
      Animated.sequence([
        Animated.timing(animatedValue, {
          toValue: 1,
          duration: 1500,
          useNativeDriver: true,
        }),
        Animated.timing(animatedValue, {
          toValue: 0,
          duration: 1500,
          useNativeDriver: true,
        }),
      ])
    ).start();
  }, []);
  const opacity = animatedValue.interpolate({
    inputRange: [0, 1],
    outputRange: [0.3, 0.7],
  });
  const getSkeletonStyle = () => {
    switch (variant) {
      case 'circular':
        return {
          width: width,
          height: width,
          borderRadius: width / 2,
        };
      case 'card':
        return {
          width: width,
          height: height,
          borderRadius: theme.borderRadius.lg,
        };
      case 'image':
        return {
          width: width,
          height: height,
          borderRadius: theme.borderRadius.md,
        };
      case 'text':
      default:
        return {
          width: width,
          height: height,
          borderRadius: theme.borderRadius.sm,
        };
    }
  };
  return (
    <Animated.View 
      style={[
        styles.skeleton, 
        getSkeletonStyle(), 
        { opacity },
        style
      ]}
    >
      <LinearGradient
        colors={[
          theme.colors.surface,
          theme.colors.card,
          theme.colors.surface,
        ]}
        start={{ x: 0, y: 0 }}
        end={{ x: 1, y: 0 }}
        style={StyleSheet.absoluteFill}
      />
    </Animated.View>
  );
}
const styles = StyleSheet.create({
  skeleton: {
    backgroundColor: theme.colors.surface,
    overflow: 'hidden',
  },
});