Skip to content

Commit 9e3a6d2

Browse files
add loading skeleton to DevCardViewScreen (#71)
1 parent e136375 commit 9e3a6d2

2 files changed

Lines changed: 93 additions & 1 deletion

File tree

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import React, { useEffect, useRef } from 'react';
2+
import { View, Animated, StyleSheet, ViewStyle } from 'react-native';
3+
import { COLORS } from '../theme/tokens';
4+
5+
interface SkeletonProps {
6+
width?: number | string;
7+
height?: number | string;
8+
borderRadius?: number;
9+
style?: ViewStyle;
10+
}
11+
12+
export const Skeleton: React.FC<SkeletonProps> = ({
13+
width,
14+
height,
15+
borderRadius = 4,
16+
style,
17+
}) => {
18+
const opacity = useRef(new Animated.Value(0.3)).current;
19+
20+
useEffect(() => {
21+
Animated.loop(
22+
Animated.sequence([
23+
Animated.timing(opacity, {
24+
toValue: 0.7,
25+
duration: 800,
26+
useNativeDriver: true,
27+
}),
28+
Animated.timing(opacity, {
29+
toValue: 0.3,
30+
duration: 800,
31+
useNativeDriver: true,
32+
}),
33+
])
34+
).start();
35+
}, [opacity]);
36+
37+
return (
38+
<Animated.View
39+
style={[
40+
styles.skeleton,
41+
{
42+
width,
43+
height,
44+
borderRadius,
45+
opacity,
46+
},
47+
style,
48+
]}
49+
/>
50+
);
51+
};
52+
53+
const styles = StyleSheet.create({
54+
skeleton: {
55+
backgroundColor: COLORS.bgElevated,
56+
},
57+
});

apps/mobile/src/screens/DevCardViewScreen.tsx

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
} from 'react-native';
1515
import { SafeAreaView } from 'react-native-safe-area-context';
1616
import { COLORS, SPACING, FONT_SIZE, BORDER_RADIUS, SHADOWS } from '../theme/tokens';
17+
import { Skeleton } from '../components/Skeleton';
1718
import { PLATFORMS, getProfileUrl, getWebViewUrl } from '@devcard/shared';
1819
import { API_BASE_URL } from '../config';
1920
import { useAuth } from '../context/AuthContext';
@@ -175,7 +176,41 @@ export default function DevCardViewScreen({ navigation, route }: Props) {
175176
if (loading) {
176177
return (
177178
<SafeAreaView style={styles.container}>
178-
<ActivityIndicator size="large" color={COLORS.primary} style={{ flex: 1 }} />
179+
<View style={styles.scrollContent}>
180+
{/* Header Skeleton */}
181+
<View style={[styles.premiumHeaderCard, { borderColor: COLORS.border }]}>
182+
<View style={styles.cardTop}>
183+
<Skeleton width={100} height={12} />
184+
<Skeleton width={20} height={20} borderRadius={10} />
185+
</View>
186+
<View style={styles.cardMid}>
187+
<Skeleton width={70} height={70} borderRadius={35} />
188+
<View style={styles.mainInfo}>
189+
<Skeleton width="80%" height={24} style={{ marginBottom: 8 }} />
190+
<Skeleton width="60%" height={16} />
191+
</View>
192+
</View>
193+
<View style={styles.cardBottom}>
194+
<Skeleton width="70%" height={10} />
195+
<Skeleton width={60} height={16} />
196+
</View>
197+
</View>
198+
199+
{/* Tiles Skeleton */}
200+
<View style={styles.tilesSection}>
201+
<Skeleton width={120} height={14} style={{ marginBottom: 12 }} />
202+
{[1, 2, 3].map(i => (
203+
<View key={i} style={styles.platformTile}>
204+
<Skeleton width={40} height={40} borderRadius={10} />
205+
<View style={[styles.tileInfo, { marginLeft: 16 }]}>
206+
<Skeleton width="50%" height={16} style={{ marginBottom: 6 }} />
207+
<Skeleton width="30%" height={12} />
208+
</View>
209+
<Skeleton width={72} height={30} borderRadius={8} />
210+
</View>
211+
))}
212+
</View>
213+
</View>
179214
</SafeAreaView>
180215
);
181216
}

0 commit comments

Comments
 (0)