diff options
Diffstat (limited to 'apps/mobile/components/TaskListSkeleton.tsx')
| -rw-r--r-- | apps/mobile/components/TaskListSkeleton.tsx | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/apps/mobile/components/TaskListSkeleton.tsx b/apps/mobile/components/TaskListSkeleton.tsx new file mode 100644 index 0000000..60e747d --- /dev/null +++ b/apps/mobile/components/TaskListSkeleton.tsx @@ -0,0 +1,119 @@ +import React, { useEffect, useRef } from 'react'; +import { + View, + StyleSheet, + Animated, + useColorScheme, +} from 'react-native'; +import { Colors } from '../constants/Colors'; + +interface SkeletonRowProps { + delay?: number; +} + +function SkeletonRow({ delay = 0 }: SkeletonRowProps) { + const colorScheme = useColorScheme() ?? 'light'; + const colors = Colors[colorScheme]; + const opacity = useRef(new Animated.Value(0.3)).current; + + useEffect(() => { + const animation = Animated.loop( + Animated.sequence([ + Animated.timing(opacity, { + toValue: 0.7, + duration: 800, + useNativeDriver: true, + delay, + }), + Animated.timing(opacity, { + toValue: 0.3, + duration: 800, + useNativeDriver: true, + }), + ]) + ); + animation.start(); + return () => animation.stop(); + }, [opacity, delay]); + + const bgColor = colorScheme === 'dark' ? '#374151' : '#e5e7eb'; + + return ( + <View + style={[ + styles.row, + { + backgroundColor: colors.card, + borderColor: colors.border, + }, + ]} + > + <Animated.View + style={[ + styles.dot, + { backgroundColor: bgColor, opacity }, + ]} + /> + <View style={styles.content}> + <Animated.View + style={[ + styles.titleBar, + { backgroundColor: bgColor, opacity }, + ]} + /> + <Animated.View + style={[ + styles.subtitleBar, + { backgroundColor: bgColor, opacity }, + ]} + /> + </View> + </View> + ); +} + +export function TaskListSkeleton() { + return ( + <View style={styles.container}> + <SkeletonRow delay={0} /> + <SkeletonRow delay={100} /> + <SkeletonRow delay={200} /> + <SkeletonRow delay={300} /> + <SkeletonRow delay={400} /> + </View> + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + row: { + flexDirection: 'row', + alignItems: 'center', + paddingVertical: 16, + paddingHorizontal: 16, + borderBottomWidth: StyleSheet.hairlineWidth, + minHeight: 64, + }, + dot: { + width: 10, + height: 10, + borderRadius: 5, + marginRight: 12, + }, + content: { + flex: 1, + gap: 8, + }, + titleBar: { + height: 16, + width: '70%', + borderRadius: 4, + }, + subtitleBar: { + height: 12, + width: '40%', + borderRadius: 4, + }, +}); |
