Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 17:56:56 +08:00
commit 9916280104
14 changed files with 5089 additions and 0 deletions

233
commands/app-scaffold.md Normal file
View File

@@ -0,0 +1,233 @@
# React Native App Scaffolding
Generate production-ready React Native application structure.
## Task
You are a React Native expert. Generate a complete, production-ready mobile app scaffold with best practices.
### Steps:
1. **Ask for Requirements**:
- App name
- Platform: Expo or bare React Native
- Navigation library: React Navigation or Expo Router
- State management: Redux, Zustand, or Context API
- UI library: React Native Paper, NativeBase, or custom
2. **Generate Project Structure**:
```
my-app/
├── app.json / package.json
├── babel.config.js
├── tsconfig.json
├── App.tsx
├── src/
│ ├── screens/
│ │ ├── HomeScreen.tsx
│ │ ├── ProfileScreen.tsx
│ │ └── SettingsScreen.tsx
│ ├── components/
│ │ ├── common/
│ │ │ ├── Button.tsx
│ │ │ ├── Input.tsx
│ │ │ └── Card.tsx
│ │ └── specific/
│ ├── navigation/
│ │ ├── AppNavigator.tsx
│ │ ├── AuthNavigator.tsx
│ │ └── types.ts
│ ├── store/ # Redux/Zustand
│ │ ├── slices/
│ │ ├── hooks.ts
│ │ └── index.ts
│ ├── services/
│ │ ├── api/
│ │ │ ├── client.ts
│ │ │ └── endpoints/
│ │ └── storage/
│ ├── hooks/
│ │ ├── useAuth.ts
│ │ ├── useAsync.ts
│ │ └── useDebounce.ts
│ ├── utils/
│ │ ├── validation.ts
│ │ └── formatting.ts
│ ├── constants/
│ │ ├── colors.ts
│ │ ├── sizes.ts
│ │ └── api.ts
│ ├── types/
│ │ └── index.ts
│ └── assets/
│ ├── images/
│ └── fonts/
├── __tests__/
└── .env.example
```
3. **Generate App Entry Point** (Expo):
```typescript
import 'react-native-gesture-handler';
import { StatusBar } from 'expo-status-bar';
import { Provider } from 'react-redux';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { NavigationContainer } from '@react-navigation/native';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { store } from './src/store';
import AppNavigator from './src/navigation/AppNavigator';
import { ErrorBoundary } from './src/components/ErrorBoundary';
const queryClient = new QueryClient();
export default function App() {
return (
<ErrorBoundary>
<Provider store={store}>
<QueryClientProvider client={queryClient}>
<SafeAreaProvider>
<NavigationContainer>
<AppNavigator />
<StatusBar style="auto" />
</NavigationContainer>
</SafeAreaProvider>
</QueryClientProvider>
</Provider>
</ErrorBoundary>
);
}
```
4. **Generate Navigation**:
```typescript
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { HomeScreen, ProfileScreen, SettingsScreen } from '../screens';
const Stack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
function TabNavigator() {
return (
<Tab.Navigator screenOptions={{ headerShown: false }}>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
export default function AppNavigator() {
const isAuthenticated = useSelector(state => state.auth.isAuthenticated);
return (
<Stack.Navigator>
{isAuthenticated ? (
<Stack.Screen name="Main" component={TabNavigator} />
) : (
<Stack.Screen name="Auth" component={AuthScreen} />
)}
</Stack.Navigator>
);
}
```
5. **Generate API Client**:
```typescript
import axios from 'axios';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { API_BASE_URL } from '../constants/api';
const api = axios.create({
baseURL: API_BASE_URL,
timeout: 10000,
});
// Request interceptor
api.interceptors.request.use(async (config) => {
const token = await AsyncStorage.getItem('auth_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// Response interceptor
api.interceptors.response.use(
(response) => response,
async (error) => {
if (error.response?.status === 401) {
await AsyncStorage.removeItem('auth_token');
// Navigate to login
}
return Promise.reject(error);
}
);
export default api;
```
6. **Generate package.json**:
```json
{
"name": "my-app",
"version": "1.0.0",
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web",
"test": "jest",
"lint": "eslint .",
"type-check": "tsc --noEmit"
},
"dependencies": {
"expo": "~49.0.0",
"react": "18.2.0",
"react-native": "0.72.0",
"@react-navigation/native": "^6.1.0",
"@react-navigation/native-stack": "^6.9.0",
"@react-navigation/bottom-tabs": "^6.5.0",
"react-native-safe-area-context": "4.6.3",
"react-native-screens": "~3.22.0",
"@reduxjs/toolkit": "^1.9.0",
"react-redux": "^8.1.0",
"@tanstack/react-query": "^4.35.0",
"axios": "^1.5.0",
"@react-native-async-storage/async-storage": "1.18.2",
"react-native-gesture-handler": "~2.12.0"
},
"devDependencies": {
"@types/react": "~18.2.14",
"typescript": "^5.1.3",
"@testing-library/react-native": "^12.3.0",
"jest": "^29.2.1"
}
}
```
### Best Practices Included:
- TypeScript configuration
- Navigation setup
- State management
- API client with interceptors
- Error boundaries
- Proper folder structure
- AsyncStorage for persistence
- Testing setup
- ESLint and TypeScript
### Example Usage:
```
User: "Scaffold Expo app with Redux and React Navigation"
Result: Complete Expo project with all configurations
```

256
commands/build-config.md Normal file
View File

@@ -0,0 +1,256 @@
# Build Configuration
Generate build configurations for iOS and Android.
## Task
You are a React Native build expert. Generate complete build configurations for production releases.
### Steps:
1. **Ask for Requirements**:
- App identifier/bundle ID
- Environment (dev, staging, prod)
- Code signing details
- Push notification setup
2. **Generate app.json** (Expo):
```json
{
"expo": {
"name": "My App",
"slug": "my-app",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "automatic",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.company.myapp",
"buildNumber": "1",
"infoPlist": {
"NSCameraUsageDescription": "This app uses the camera to...",
"NSPhotoLibraryUsageDescription": "This app accesses photos to...",
"NSLocationWhenInUseUsageDescription": "This app uses location to..."
},
"config": {
"googleMapsApiKey": "YOUR_KEY_HERE"
}
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"package": "com.company.myapp",
"versionCode": 1,
"permissions": [
"CAMERA",
"READ_EXTERNAL_STORAGE",
"WRITE_EXTERNAL_STORAGE",
"ACCESS_FINE_LOCATION"
],
"config": {
"googleMaps": {
"apiKey": "YOUR_KEY_HERE"
}
}
},
"plugins": [
"expo-camera",
"expo-location",
[
"expo-notifications",
{
"icon": "./assets/notification-icon.png",
"color": "#ffffff"
}
]
],
"extra": {
"eas": {
"projectId": "your-project-id"
}
}
}
}
```
3. **Generate eas.json** (Expo EAS Build):
```json
{
"cli": {
"version": ">= 5.0.0"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"ios": {
"simulator": true
}
},
"preview": {
"distribution": "internal",
"ios": {
"simulator": false,
"resourceClass": "m-medium"
},
"android": {
"buildType": "apk",
"gradleCommand": ":app:assembleRelease"
}
},
"production": {
"ios": {
"resourceClass": "m-medium",
"autoIncrement BuildNumber": true
},
"android": {
"buildType": "app-bundle",
"autoIncrement VersionCode": true
}
}
},
"submit": {
"production": {
"ios": {
"appleId": "your@email.com",
"ascAppId": "1234567890",
"appleTeamId": "ABCD1234"
},
"android": {
"serviceAccountKeyPath": "./service-account.json",
"track": "production"
}
}
}
}
```
4. **Generate Environment Variables**:
```typescript
// config/env.ts
import Constants from 'expo-constants';
const ENV = {
dev: {
apiUrl: 'http://localhost:3000',
environment: 'development',
},
staging: {
apiUrl: 'https://staging-api.example.com',
environment: 'staging',
},
prod: {
apiUrl: 'https://api.example.com',
environment: 'production',
},
};
const getEnvVars = (env = Constants.manifest?.releaseChannel) => {
if (__DEV__) return ENV.dev;
if (env === 'staging') return ENV.staging;
return ENV.prod;
};
export default getEnvVars();
```
5. **Generate Build Scripts**:
```json
// package.json scripts
{
"scripts": {
"build:dev:ios": "eas build --profile development --platform ios",
"build:dev:android": "eas build --profile development --platform android",
"build:preview:ios": "eas build --profile preview --platform ios",
"build:preview:android": "eas build --profile preview --platform android",
"build:prod:ios": "eas build --profile production --platform ios",
"build:prod:android": "eas build --profile production --platform android",
"build:prod:all": "eas build --profile production --platform all",
"submit:ios": "eas submit --platform ios",
"submit:android": "eas submit --platform android"
}
}
```
6. **Generate CI/CD Configuration** (GitHub Actions):
```yaml
name: EAS Build
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18
cache: 'npm'
- name: Setup Expo
uses: expo/expo-github-action@v8
with:
expo-version: latest
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build iOS
run: eas build --profile production --platform ios --non-interactive
if: github.ref == 'refs/heads/main'
- name: Build Android
run: eas build --profile production --platform android --non-interactive
if: github.ref == 'refs/heads/main'
- name: Submit to stores
run: |
eas submit --platform ios --non-interactive
eas submit --platform android --non-interactive
if: github.ref == 'refs/heads/main'
```
### Best Practices Included:
- Multi-environment configuration
- Proper permissions setup
- Code signing automation
- CI/CD integration
- Auto-increment version numbers
- Proper asset management
- Push notification setup
### Example Usage:
```
User: "Set up production build for iOS and Android"
Result: Complete build configuration with EAS, CI/CD, environment management
```

289
commands/screen-generate.md Normal file
View File

@@ -0,0 +1,289 @@
# Screen Generator
Generate React Native screens with navigation integration.
## Task
You are a React Native expert. Generate complete, production-ready screens with proper typing and navigation.
### Steps:
1. **Ask for Requirements**:
- Screen name and purpose
- Required data/API calls
- Form inputs (if any)
- Navigation params
2. **Generate Screen Component**:
```typescript
import React, { useEffect, useState } from 'react';
import {
View,
Text,
StyleSheet,
FlatList,
RefreshControl,
ActivityIndicator,
} from 'react-native';
import { NativeStackScreenProps } from '@react-navigation/native-stack';
import { useQuery, useMutation } from '@tanstack/react-query';
import { api } from '../../services/api';
import { Product } from '../../types';
import { ProductCard } from '../../components/ProductCard';
import { RootStackParamList } from '../../navigation/types';
type Props = NativeStackScreenProps<RootStackParamList, 'ProductList'>;
export function ProductListScreen({ navigation, route }: Props) {
const { category } = route.params;
// Fetch data with React Query
const {
data: products,
isLoading,
error,
refetch,
isRefetching,
} = useQuery({
queryKey: ['products', category],
queryFn: () => api.getProducts({ category }),
});
// Handle item press
const handleProductPress = (productId: string) => {
navigation.navigate('ProductDetail', { productId });
};
// Render loading state
if (isLoading) {
return (
<View style={styles.centerContainer}>
<ActivityIndicator size="large" />
</View>
);
}
// Render error state
if (error) {
return (
<View style={styles.centerContainer}>
<Text style={styles.errorText}>
Failed to load products
</Text>
</View>
);
}
// Render list
return (
<View style={styles.container}>
<FlatList
data={products}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<ProductCard
product={item}
onPress={() => handleProductPress(item.id)}
/>
)}
contentContainerStyle={styles.listContent}
refreshControl={
<RefreshControl
refreshing={isRefetching}
onRefresh={refetch}
/>
}
ListEmptyComponent={
<Text style={styles.emptyText}>
No products found
</Text>
}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
centerContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
listContent: {
padding: 16,
},
errorText: {
fontSize: 16,
color: 'red',
},
emptyText: {
fontSize: 16,
textAlign: 'center',
marginTop: 32,
},
});
```
3. **Generate Form Screen**:
```typescript
import React from 'react';
import {
View,
StyleSheet,
ScrollView,
KeyboardAvoidingView,
Platform,
} from 'react-native';
import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';
import { Input } from '../../components/Input';
import { Button } from '../../components/Button';
import { api } from '../../services/api';
const schema = z.object({
name: z.string().min(1, 'Name is required'),
email: z.string().email('Invalid email'),
phone: z.string().regex(/^\d{10}$/, 'Invalid phone number'),
});
type FormData = z.infer<typeof schema>;
export function ProfileEditScreen({ navigation }: Props) {
const {
control,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<FormData>({
resolver: zodResolver(schema),
defaultValues: {
name: '',
email: '',
phone: '',
},
});
const onSubmit = async (data: FormData) => {
try {
await api.updateProfile(data);
navigation.goBack();
} catch (error) {
console.error('Failed to update profile', error);
}
};
return (
<KeyboardAvoidingView
style={styles.container}
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
>
<ScrollView
contentContainerStyle={styles.content}
keyboardShouldPersistTaps="handled"
>
<Controller
control={control}
name="name"
render={({ field: { onChange, value } }) => (
<Input
label="Name"
value={value}
onChangeText={onChange}
error={errors.name?.message}
/>
)}
/>
<Controller
control={control}
name="email"
render={({ field: { onChange, value } }) => (
<Input
label="Email"
value={value}
onChangeText={onChange}
keyboardType="email-address"
autoCapitalize="none"
error={errors.email?.message}
/>
)}
/>
<Controller
control={control}
name="phone"
render={({ field: { onChange, value } }) => (
<Input
label="Phone"
value={value}
onChangeText={onChange}
keyboardType="phone-pad"
error={errors.phone?.message}
/>
)}
/>
<Button
title="Save"
onPress={handleSubmit(onSubmit)}
loading={isSubmitting}
/>
</ScrollView>
</KeyboardAvoidingView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
content: {
padding: 16,
},
});
```
4. **Generate Navigation Types**:
```typescript
// navigation/types.ts
export type RootStackParamList = {
ProductList: { category: string };
ProductDetail: { productId: string };
ProfileEdit: undefined;
};
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackParamList {}
}
}
```
### Best Practices Included:
- TypeScript types
- React Query for data fetching
- React Hook Form for forms
- Zod validation
- Proper error handling
- Loading states
- Pull-to-refresh
- Keyboard handling
- Responsive styling
### Example Usage:
```
User: "Generate product list screen with pull-to-refresh"
Result: Complete screen with navigation, data fetching, error handling
```