Files
RN_Template/RN_TEMPLATE/CLAUDE.md
2026-02-05 13:16:05 +08:00

315 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## user rools
每次开头请叫我哥哥
请严格遵守ui设计规范使用响应式布局设计不要硬编码
请使用项目里面封装好的ui组件如果没有请提醒我
## Project Overview
React Native + Expo mobile application built on **Ignite CLI boilerplate** (v11.4.0). Uses TypeScript, React Navigation 7, and NativeWind (Tailwind CSS).
## Common Commands
```bash
pnpm install # Install dependencies
pnpm run start # Start Expo dev client
pnpm run android # Run on Android (expo run:android)
pnpm run ios # Run on iOS (expo run:ios)
pnpm run compile # TypeScript type check (tsc --noEmit)
pnpm run lint # ESLint with auto-fix
pnpm run lint:check # ESLint without fix
pnpm run test # Run Jest tests
pnpm run test:watch # Run Jest in watch mode
# EAS Builds (requires expo-cli)
pnpm run build:ios:sim # iOS simulator build
pnpm run build:android:sim # Android emulator build
pnpm run prebuild:clean # Regenerate native projects
```
## Architecture
### Directory Structure
- `app/` - Main application source
- `components/` - 12个基础 UI 组件(详见下方组件列表)
- `screens/` - Screen components connected to navigation
- `screens/DemoShowroomScreen/demos/` - 组件演示页面(展示组件用法,非实际组件)
- `navigators/` - React Navigation configuration (AppNavigator, DemoNavigator)
- `context/` - React Context providers (AuthContext, ThemeContext, ToastContext)
- `services/api/` - API layer using Apisauce (`authApi.ts` for auth, `index.ts` for base API)
- `theme/` - Design tokens (colors, spacing, typography) and theme system
- `i18n/` - Internationalization with i18next (8 languages: en, zh, ar, es, fr, hi, ja, ko)
- `utils/` - Utilities including MMKV storage wrapper
- `config/` - Environment-based configuration (dev/prod)
- `devtools/` - Reactotron configuration
### Key Patterns
**State Management**: React Context + MMKV for persistence. No Redux.
**Theming**: Use `useAppTheme()` hook and `ThemedStyle<T>` pattern:
```typescript
const $container: ThemedStyle<ViewStyle> = ({ colors, spacing }) => ({
backgroundColor: colors.background,
padding: spacing.lg,
})
```
**Navigation**: Two-layer structure - AppStack (auth/main screens) and DemoNavigator (bottom tabs). Type-safe routes defined in `navigationTypes.ts`. Auth screens: AuthWelcome, Login, Register, ForgotPassword. Main screens: Welcome, Profile, Settings, Security, Theme, Language, About, etc.
**API Layer**: Singleton `Api` class in `services/api/index.ts` using Apisauce with typed responses.
**Styling**: NativeWind (Tailwind CSS) configured. Use `className` prop for Tailwind styles.
**Authentication**: `AuthContext` provides full auth flow with step-based state machines for login, register, and password reset. Supports email/password and Google Sign-In. Uses JWT tokens stored in MMKV.
## UI 设计规范
### 参考文件
| 类型 | 文件路径 | 说明 |
|------|----------|------|
| **设计令牌** | `app/theme/colors.ts` | 颜色系统(浅色主题) |
| | `app/theme/colorsDark.ts` | 颜色系统(深色主题) |
| | `app/theme/spacing.ts` | 间距系统 |
| | `app/theme/typography.ts` | 字体排版 |
| | `app/theme/styles.ts` | 全局样式($styles.container 等) |
| **UI 参考页面** | `app/screens/DemoCommunityScreen.tsx` | **最佳参考** - 标准页面结构、ListItem 用法、Section 标题 |
| | `app/screens/WelcomeScreen.tsx` | useHeader hook 用法 |
| | `app/screens/ProfileScreen.tsx` | 设置页面、用户卡片 |
| **组件演示** | `app/screens/DemoShowroomScreen/demos/` | 所有组件的用法示例(类似 Storybook |
### 设计令牌
**颜色语义**(定义在 `app/theme/colors.ts`:
```typescript
text: palette.neutral800 // 主要文本
textDim: palette.neutral600 // 次要文本
background: palette.neutral200 // 屏幕背景
border: palette.neutral400 // 边框
tint: palette.primary500 // 主色调(按钮、链接)
separator: palette.neutral300 // 分隔线
error: palette.angry500 // 错误
```
**间距系统**`app/theme/spacing.ts`:
```typescript
xxxs: 2, xxs: 4, xs: 8, sm: 12, md: 16, lg: 24, xl: 32, xxl: 48, xxxl: 64
```
**字体大小**`app/components/Text.tsx`:
```typescript
xxl: 36, xl: 24, lg: 20, md: 18, sm: 16(默认), xs: 14, xxs: 12
```
### Header 使用规范
**必须使用 `useHeader` hook**,不要直接在 Screen 内部放置 `<Header>` 组件。
```typescript
// ✅ 正确写法
import { useHeader } from "@/utils/useHeader"
useHeader({
title: translate("screenName:title"),
leftIcon: "back",
onLeftPress: () => navigation.goBack(),
}, [])
return (
<Screen safeAreaEdges={["bottom"]} contentContainerStyle={[$styles.container, themed($container)]}>
{/* 内容 */}
</Screen>
)
const $container: ThemedStyle<ViewStyle> = ({ spacing }) => ({
paddingTop: spacing.lg, // 覆盖 $styles.container 的 56px
})
```
**原因**: Header 组件默认添加顶部安全区域 padding直接放在 Screen 内容中会导致 Header 上方出现额外空白。`useHeader` 通过 `navigation.setOptions()` 将 Header 设置为导航层的一部分。
### 容器间距规范
`$styles.container`(定义在 `app/theme/styles.ts`:
```typescript
container: {
paddingTop: spacing.lg + spacing.xl, // = 56px为无 Header 的 Tab 页面设计)
paddingHorizontal: spacing.lg, // = 24px
}
```
**使用 useHeader 的页面**需在 `$container` 中覆盖 paddingTop 为 `spacing.lg` (24px)。
**不要**在页面内容中再添加额外的 paddingTop 或 marginTop避免重复间距。
### ListItem 使用规范
**参考**: `app/screens/DemoCommunityScreen.tsx`
**默认无分隔线**,保持简洁风格:
```typescript
<ListItem
tx="setting:option1"
leftIcon="settings"
rightIcon="caretRight"
onPress={handlePress}
/>
```
只有**连续列表项**需要视觉分隔时,才使用 `bottomSeparator`,且**最后一项不需要**:
```typescript
<ListItem text="Item 1" bottomSeparator />
<ListItem text="Item 2" bottomSeparator />
<ListItem text="Item 3" />
```
### Section 标题规范
**参考**: `app/screens/DemoCommunityScreen.tsx``$sectionTitle` 样式
使用 `preset="subheading"` 作为 section 标题:
```typescript
<Text preset="subheading" tx="section:title" style={themed($sectionTitle)} />
const $sectionTitle: ThemedStyle<TextStyle> = ({ spacing }) => ({
marginTop: spacing.xxl, // 48px
})
```
### 页面结构模板
**有 Header 的页面**(如设置、详情页):
```typescript
import { useHeader } from "@/utils/useHeader"
export const ExampleScreen: FC<Props> = ({ navigation }) => {
const { themed } = useAppTheme()
useHeader({
title: translate("exampleScreen:title"),
leftIcon: "back",
onLeftPress: () => navigation.goBack(),
}, [])
return (
<Screen
preset="scroll"
safeAreaEdges={["bottom"]}
contentContainerStyle={[$styles.container, themed($container)]}
>
{/* 内容 */}
</Screen>
)
}
const $container: ThemedStyle<ViewStyle> = ({ spacing }) => ({
paddingTop: spacing.lg,
})
```
**无 Header 的 Tab 页面**(参考 `DemoCommunityScreen.tsx`:
```typescript
export const ExampleTabScreen: FC<Props> = () => {
const { themed } = useAppTheme()
return (
<Screen preset="scroll" contentContainerStyle={$styles.container}>
<Text preset="heading" tx="screen:title" style={themed($title)} />
<Text tx="screen:description" style={themed($description)} />
<Text preset="subheading" tx="screen:section1" style={themed($sectionTitle)} />
<ListItem ... />
<ListItem ... />
</Screen>
)
}
const $title: ThemedStyle<TextStyle> = ({ spacing }) => ({
marginBottom: spacing.sm,
})
const $description: ThemedStyle<TextStyle> = ({ spacing }) => ({
marginBottom: spacing.lg,
})
const $sectionTitle: ThemedStyle<TextStyle> = ({ spacing }) => ({
marginTop: spacing.xxl,
})
```
### 组件列表 (`app/components/`)
| 组件 | 用途 |
|------|------|
| `Screen.tsx` | 屏幕容器SafeArea + 键盘适配 + 滚动) |
| `Header.tsx` | 页面头部导航栏 |
| `Card.tsx` | 卡片容器 |
| `TextField.tsx` | 文本输入框 |
| `Button.tsx` | 按钮default/filled/reversed 预设) |
| `EmptyState.tsx` | 空状态占位 |
| `ListItem.tsx` | 列表项 |
| `Icon.tsx` | 图标 |
| `Text.tsx` | 文本heading/subheading/bold 等预设) |
| `AutoImage.tsx` | 自适应图片 |
| `Toggle/` | 开关/复选框/单选框 |
| `Avatar.tsx` | 用户头像(使用 expo-image 缓存) |
| `Modal.tsx` | 模态框bottom/center 预设) |
| `Dialog.tsx` | 对话框(确认/提示) |
**注意**: `screens/DemoShowroomScreen/demos/` 目录下的 `Demo*.tsx` 文件是组件**演示页面**,用于展示组件的各种用法和变体,类似 Storybook不是实际组件。
### 自适应布局
**Screen 组件预设**:
- `preset="fixed"` - 固定布局,不可滚动
- `preset="scroll"` - 始终可滚动
- `preset="auto"` - 智能判断:内容超出屏幕时才启用滚动
**安全区域**: 使用 `useSafeAreaInsetsStyle` hook 处理刘海屏
```typescript
<Screen safeAreaEdges={["top", "bottom"]}>
{/* 内容自动避开刘海和底部指示条 */}
</Screen>
```
**间距系统** (`app/theme/spacing.ts`):
```typescript
xxxs: 2, xxs: 4, xs: 8, sm: 12, md: 16, lg: 24, xl: 32, xxl: 48, xxxl: 64
```
**字体大小** (`app/components/Text.tsx`) - 固定像素值,无响应式:
```typescript
xxl: 36, xl: 24, lg: 20, md: 18, sm: 16(默认), xs: 14, xxs: 12
```
### Path Aliases
- `@/*``app/*`
- `@assets/*``assets/*`
## Import Restrictions (ESLint enforced)
- Use `Text`, `Button`, `TextInput` from `@/components`, not from `react-native`
- Use `SafeAreaView` from `react-native-safe-area-context`, not from `react-native`
- Import named exports from `react` (not `import React from 'react'`)
## Testing
Jest with Testing Library for React Native. Test files use `.test.ts(x)` suffix. Setup in `test/setup.ts`.
Run single test:
```bash
pnpm run test -- --testPathPattern="storage"
```
## Web Support
This app runs on web via Expo. Use `pnpm run start` and press `w` to open web. Note: React Navigation's `headerRight` may not work reliably on web - consider placing header elements directly inside Screen components if targeting web.
## Running on Physical Devices