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:
Claude
2025-11-15 01:10:55 +00:00
parent 8c905183fd
commit 3d84b618cf
9 changed files with 1827 additions and 0 deletions
+111
View File
@@ -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,
},
});