Skip to main content

معلومات المصدر

المستودع
miles990/claude-software-skills
آخر نشاط في المصدر
١٥ يناير ٢٠٢٦ في ٠٧:٥٨
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٢٦
التفرعات
٦

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
5 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
mobile
description
Mobile development with React Native, Flutter, and native patterns
domain
development-stacks
version
1.0.0
tags
["react-native","flutter","ios","android","expo","mobile-ui"]
triggers
{"keywords":{"primary":["mobile","react native","flutter","ios","android","app","expo"],"secondary":["navigation","push notification","deep link","gesture","native module"]},"context_boost":["app store","play store","cross-platform","hybrid"],"context_penalty":["web","backend","desktop","server"],"priority":"high"}
# Mobile Development ## Overview Cross-platform and native mobile development patterns, frameworks, and best practices. --- ## React Native ### Component Patterns ```tsx // Functional component with hooks import React, { useState, useCallback } from 'react'; import { View, Text, FlatList, TouchableOpacity, StyleSheet, RefreshControl, } from 'react-native'; interface User { id: string; name: string; email: string; } interface UserListProps { users: User[]; onSelect: (user: User) => void; onRefresh: () => Promise<void>; } export function UserList({ users, onSelect, onRefresh }: UserListProps) { const [refreshing, setRefreshing] = useState(false); const handleRefresh = useCallback(async () => { setRefreshing(true); await onRefresh(); setRefreshing(false); }, [onRefresh]); const renderItem = useCallback(({ item }: { item: User }) => ( <TouchableOpacity style={styles.item} onPress={() => onSelect(item)} activeOpacity={0.7} > <Text style={styles.name}>{item.name}</Text> <Text style={styles.email}>{item.email}</Text> </TouchableOpacity> ), [onSelect]); const keyExtractor = useCallback((item: User) => item.id, []); return ( <FlatList data={users} renderItem={renderItem} keyExtractor={keyExtractor} refreshControl={ <RefreshControl refreshing={refreshing} onRefresh={handleRefresh} /> } ItemSeparatorComponent={() => <View style={styles.separator} />} ListEmptyComponent={ <Text style={styles.empty}>No users found</Text> } /> ); } const styles = StyleSheet.create({ item: { padding: 16, backgroundColor: '#fff', }, name: { fontSize: 16, fontWeight: '600', color: '#1a1a1a', }, email: { fontSize: 14, color: '#666', marginTop: 4, }, separator: { height: 1, backgroundColor: '#e0e0e0', }, empty: { textAlign: 'center', padding: 32, color: '#999', }, }); ``` ### Navigation ```tsx // React Navigation setup import { NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; // Type-safe navigation type RootStackParamList = { Home: undefined; Profile: { userId: string }; Settings: undefined; }; type TabParamList = { Feed: undefined; Search: undefined; Notifications: undefined; Account: undefined; }; const Stack = createNativeStackNavigator<RootStackParamList>(); const Tab = createBottomTabNavigator<TabParamList>(); function TabNavigator() { return ( <Tab.Navigator screenOptions={({ route }) => ({ tabBarIcon: ({ focused, color, size }) => { const iconName = { Feed: focused ? 'home' : 'home-outline', Search: focused ? 'search' : 'search-outline', Notifications: focused ? 'bell' : 'bell-outline', Account: focused ? 'person' : 'person-outline', }[route.name]; return <Icon name={iconName} size={size} color={color} />; }, tabBarActiveTintColor: '#007AFF', tabBarInactiveTintColor: '#8E8E93', })} > <Tab.Screen name="Feed" component={FeedScreen} /> <Tab.Screen name="Search" component={SearchScreen} /> <Tab.Screen name="Notifications" component={NotificationsScreen} /> <Tab.Screen name="Account" component={AccountScreen} /> </Tab.Navigator> ); } function App() { return ( <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Home" component={TabNavigator} options={{ headerShown: false }} /> <Stack.Screen name="Profile" component={ProfileScreen} options={{ title: 'User Profile' }} /> <Stack.Screen name="Settings" component={SettingsScreen} /> </Stack.Navigator> </NavigationContainer> ); } // Using navigation in components import { useNavigation, useRoute } from '@react-navigation/native'; import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; type ProfileScreenNavigationProp = NativeStackNavigationProp< RootStackParamList, 'Profile' >; function ProfileButton({ userId }: { userId: string }) { const navigation = useNavigation<ProfileScreenNavigationProp>(); return ( <Button title="View Profile" onPress={() => navigation.navigate('Profile', { userId })} /> ); } ``` ### State Management ```tsx // Zustand for React Native import { create } from 'zustand'; import { persist, createJSONStorage } from 'zustand/middleware'; import AsyncStorage from '@react-native-async-storage/async-storage'; interface AuthState { user: User | null; token: string | null; login: (email: string, password: string) => Promise<void>; logout: () => void; } const useAuthStore = create<AuthState>()( persist( (set) => ({ user: null, token: null, login: async (email, password) => { const response = await api.login(email, password); set({ user: response.user, token: response.token }); }, logout: () => { set({ user: null, token: null }); }, }), { name: 'auth-storage', storage: createJSONStorage(() => AsyncStorage), } ) ); // React Query for data fetching import { useQuery, useMutation, QueryClient } from '@tanstack/react-query'; const queryClient = new QueryClient({ defaultOptions: { queries: { retry: 2, staleTime: 5 * 60 * 1000, }, }, }); function usePosts() { return useQuery({ queryKey: ['posts'], queryFn: () => api.getPosts(), }); } function useCreatePost() { return useMutation({ mutationFn: (newPost: CreatePostInput) => api.createPost(newPost), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['posts'] }); }, }); } ``` ### Platform-Specific Code ```tsx import { Platform, StyleSheet } from 'react-native'; const styles = StyleSheet.create({ container: { paddingTop: Platform.OS === 'ios' ? 44 : 0, ...Platform.select({ ios: { shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, }, android: { elevation: 4, }, }), }, }); // Platform-specific files // Button.ios.tsx // Button.android.tsx // Import as: import { Button } from './Button'; ``` --- ## Expo ### Expo Router ```tsx // app/_layout.tsx import { Stack } from 'expo-router'; export default function RootLayout() { return ( <Stack> <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> <Stack.Screen name="modal" options={{ presentation: 'modal' }} /> </Stack> ); } // app/(tabs)/_layout.tsx import { Tabs } from 'expo-router'; import { Ionicons } from '@expo/vector-icons'; export default function TabLayout() { return ( <Tabs> <Tabs.Screen name="index" options={{ title: 'Home', tabBarIcon: ({ color }) => ( <Ionicons name="home" size={24} color={color} /> ), }} /> <Tabs.Screen name="profile" options={{ title: 'Profile', tabBarIcon: ({ color }) => ( <Ionicons name="person" size={24} color={color} /> ), }} /> </Tabs> ); } // app/(tabs)/index.tsx import { View, Text } from 'react-native'; import { Link } from 'expo-router'; export default function HomeScreen() { return ( <View> <Text>Home Screen</Text> <Link href="/profile">Go to Profile</Link> <Link href="/modal">Open Modal</Link> </View> ); } ``` ### Native APIs ```tsx import * as Camera from 'expo-camera'; import * as ImagePicker from 'expo-image-picker'; import * as Location from 'expo-location'; import * as Notifications from 'expo-notifications'; // Camera async function takePhoto() { const { status } = await Camera.requestCameraPermissionsAsync(); if (status !== 'granted') { Alert.alert('Permission required', 'Camera access is needed'); return; } const result = await ImagePicker.launchCameraAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, quality: 0.8, }); if (!result.canceled) { return result.assets[0].uri; } } // Location async function getCurrentLocation() { const { status } = await Location.requestForegroundPermissionsAsync(); if (status !== 'granted') { throw new Error('Location permission denied'); } const location = await Location.getCurrentPositionAsync({}); return { latitude: location.coords.latitude, longitude: location.coords.longitude, }; } // Push Notifications async function registerForPushNotifications() { const { status } = await Notifications.requestPermissionsAsync(); if (status !== 'granted') { return null; } const token = await Notifications.getExpoPushTokenAsync(); return token.data; } Notifications.setNotificationHandler({ handleNotification: async () => ({ shouldShowAlert: true, shouldPlaySound: true, shouldSetBadge: true, }), }); ``` --- ## Flutter ### Widget Patterns ```dart // Stateless widget class UserCard extends StatelessWidget { final User user; final VoidCallback onTap; const UserCard({ super.key, required this.user, required this.onTap, }); @override Widget build(BuildContext context) { return Card( child: ListTile( leading: CircleAvatar( backgroundImage: NetworkImage(user.avatarUrl), ), title: Text(user.name), subtitle: Text(user.email), trailing: const Icon(Icons.chevron_right), onTap: onTap, ), ); } } // Stateful widget with hooks (flutter_hooks) class CounterPage extends HookWidget { @override Widget build(BuildContext context) { final count = useState(0); final controller = useAnimationController(duration: Duration(seconds: 1)); return Scaffold( body: Center( child: Text('Count: ${count.value}'), ), floatingActionButton: FloatingActionButton( onPressed: () => count.value++, child: const Icon(Icons.add), ), ); } } ```
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub