mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-25 11:57:56 +00:00
Add world-class mobile components and Staking/Governance screens
PHASE 1 & 2 of mobile app transformation completed. New Modern Component Library: - Card: Elevated, outlined, filled variants with press states - Button: 5 variants (primary, secondary, outline, ghost, danger) with Kurdistan colors - Input: Floating labels, validation, icons, focus states - BottomSheet: Swipe-to-dismiss modal with smooth animations - LoadingSkeleton: Shimmer loading states (Skeleton, CardSkeleton, ListItemSkeleton) - Badge: Status indicators and labels for Tiki roles New Screens: 1. StakingScreen (504 lines): - View staked amount and rewards - Live staking data from blockchain - Stake/Unstake with bottom sheets - Tiki score breakdown - Monthly PEZ rewards calculation - APY estimation - Unbonding status - Inspired by Polkadot.js and Argent 2. GovernanceScreen (447 lines): - Active proposals list - Vote FOR/AGAINST proposals - Real-time voting statistics - Vote progress visualization - Proposal details bottom sheet - Democratic participation interface - Inspired by modern DAO platforms Design Principles: ✅ Kurdistan colors (Kesk, Sor, Zer) throughout ✅ Material Design 3 inspired ✅ Smooth animations and transitions ✅ Clean, modern UI ✅ Accessibility-first ✅ RTL support ready All components use: - Shared theme from @pezkuwi/theme - Shared blockchain logic from @pezkuwi/lib - TypeScript with full type safety - React Native best practices Next: DEX/Swap, NFT Gallery, Transaction History
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { View, Animated, StyleSheet, ViewStyle } from 'react-native';
|
||||
import { AppColors } from '../theme/colors';
|
||||
|
||||
interface SkeletonProps {
|
||||
width?: number | string;
|
||||
height?: number;
|
||||
borderRadius?: number;
|
||||
style?: ViewStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loading Skeleton Component
|
||||
* Shimmer animation for loading states
|
||||
*/
|
||||
export const Skeleton: React.FC<SkeletonProps> = ({
|
||||
width = '100%',
|
||||
height = 20,
|
||||
borderRadius = 8,
|
||||
style,
|
||||
}) => {
|
||||
const animatedValue = useRef(new Animated.Value(0)).current;
|
||||
|
||||
useEffect(() => {
|
||||
Animated.loop(
|
||||
Animated.sequence([
|
||||
Animated.timing(animatedValue, {
|
||||
toValue: 1,
|
||||
duration: 1000,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
Animated.timing(animatedValue, {
|
||||
toValue: 0,
|
||||
duration: 1000,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
])
|
||||
).start();
|
||||
}, []);
|
||||
|
||||
const opacity = animatedValue.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0.3, 0.7],
|
||||
});
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.skeleton,
|
||||
{ width, height, borderRadius, opacity },
|
||||
style,
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Card Skeleton for loading states
|
||||
*/
|
||||
export const CardSkeleton: React.FC = () => (
|
||||
<View style={styles.cardSkeleton}>
|
||||
<Skeleton width="60%" height={24} style={{ marginBottom: 12 }} />
|
||||
<Skeleton width="40%" height={16} style={{ marginBottom: 8 }} />
|
||||
<Skeleton width="80%" height={16} style={{ marginBottom: 16 }} />
|
||||
<View style={styles.row}>
|
||||
<Skeleton width={60} height={32} borderRadius={16} />
|
||||
<Skeleton width={80} height={32} borderRadius={16} />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
/**
|
||||
* List Item Skeleton
|
||||
*/
|
||||
export const ListItemSkeleton: React.FC = () => (
|
||||
<View style={styles.listItem}>
|
||||
<Skeleton width={48} height={48} borderRadius={24} />
|
||||
<View style={styles.listItemContent}>
|
||||
<Skeleton width="70%" height={16} style={{ marginBottom: 8 }} />
|
||||
<Skeleton width="40%" height={14} />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
skeleton: {
|
||||
backgroundColor: AppColors.border,
|
||||
},
|
||||
cardSkeleton: {
|
||||
backgroundColor: AppColors.surface,
|
||||
borderRadius: 16,
|
||||
padding: 16,
|
||||
marginBottom: 16,
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
gap: 12,
|
||||
},
|
||||
listItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
padding: 16,
|
||||
gap: 12,
|
||||
backgroundColor: AppColors.surface,
|
||||
borderRadius: 12,
|
||||
marginBottom: 8,
|
||||
},
|
||||
listItemContent: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user