# Card UI（技术计划）

## 1. 计划目标

在卡片页（`/(app)/home`）完成 UI 与交互升级：

- 右上角两个圆形图标按钮：
  - 主题切换（`theme.svg`）→ 打开主题弹窗
  - 个人主页（`my.svg`）→ 打开个人主页弹窗
- 两个弹窗统一视觉规范：**弹窗内容区背景色 `#FAF3EC`**、圆角、遮罩、关闭交互一致
- 卡片页底部「讨厌/喜欢」从文字按钮改为图标按钮（`hate.svg`、`like.svg`），点击有动效

## 2. 默认技术决策

- **路由**：沿用 `expo-router`（不新增 modal route，弹窗优先用页面内 `Modal` 承载，降低路由复杂度）
- **动效**：优先使用已存在的 `react-native-reanimated`（按压缩放/回弹等）
- **SVG 渲染**：使用 `react-native-svg` + 新增 `react-native-svg-transformer`，让本地 `.svg` 可直接 `import` 为组件
- **持久化**：沿用 `AsyncStorage`（在 `src/storage/appStorage.ts` 统一封装 key）

## 3. 资源与命名约定

图标资源位置：`client/assets/images/home/`

- `theme.svg`：主题入口
- `my.svg`：个人主页入口
- `like.svg`：喜欢
- `hate.svg`：讨厌（逻辑层仍沿用 reaction=`dislike`，仅资源命名为 hate）

## 4. UI 与交互实现设计

### 4.1 右上角双按钮（主题 / 我的）

落点：`client/app/(app)/_layout.tsx`

- 将 `home` 的 `headerRight` 改为两个 icon 按钮容器（水平排列）
- 统一按钮样式：圆形底、浅色背景、`hitSlop>=10`
- 点击行为：
  - 主题按钮：触发 Home 页打开「主题弹窗」
  - 我的按钮：触发 Home 页打开「个人主页弹窗」

> 实现方式：`headerRight` 只负责“发出事件”，弹窗的实际 UI 放在 `home.tsx` 内（避免把复杂 UI 塞进导航 header）。

事件方案（两种可选，优先 A）：

- A：使用一个轻量全局状态（例如在 `home` 内通过 `useFocusEffect` + `router` 事件不太合适）  
  - 更推荐：把 header 做成 Home 页内部自绘顶部栏（`headerShown:false`），所有状态都留在页面内
- B：继续用导航 header，但通过 `React.Context` 或一个简易 store（如 Zustand，若项目未引入则先不加）把“打开弹窗”动作传给页面

本计划默认采用 **A（Home 页自绘顶部栏）**，因为实现最直接、样式可控、无跨层状态传递。

### 4.2 主题弹窗（背景色 #FAF3EC）

落点建议：

- `client/components/home/ThemeModal.tsx`
- `client/components/ui/SheetModal.tsx`（复用：遮罩、圆角容器、上滑/淡入动效、关闭逻辑）

交互：

- 点击主题按钮 → 打开弹窗
- 选择「风景 / 颜色」→ 立即写入主题 mode + 关闭（或保持打开并高亮选中，按设计稿）
- 点击遮罩 / 关闭按钮 → 关闭

视觉：

- 弹窗内容区背景：`#FAF3EC`
- 容器圆角与内边距按设计稿（默认 24 圆角、16–20 padding）

### 4.3 个人主页弹窗（背景色 #FAF3EC）

落点建议：

- `client/components/home/ProfileModal.tsx`
- 复用 `SheetModal`

内容与导航：

- 顶部：插画/头像 + 昵称（来自 `getUserProfile().name`，无则显示占位名）
- 快捷卡片：我的喜欢 / 小组件（按现有设计稿与已有页面映射）
- 通用列表：每日提醒 / 隐私政策 / 使用条款 / 语言

页面/能力映射（一期最小闭环）：

- 我的喜欢 → 跳转到 `/(app)/favorites`
- 语言 → 跳转到现有语言设置页（若尚未落地，则在本次实现中补齐入口或先占位）
- 隐私政策 / 使用条款 → 复用 Splash Consent 的外链打开方式（或后续统一到一个 WebView 组件）
- 每日提醒 → 若现有页面未实现，先占位并在 tasks 阶段拆分

### 4.4 喜欢 / 讨厌按钮改为 icon + 动效

落点：`client/app/(app)/home.tsx`

- 将底部两个 `Pressable + Text` 按钮替换为 icon 按钮：
  - 喜欢：`like.svg`
  - 讨厌：`hate.svg`
- 点击动效（建议）：
  - `pressIn`：scale 到 0.92
  - `pressOut`：回弹到 1
  - `onPress`：短促 “弹一下” 的强调动效（例如 scale 1 → 1.12 → 1），随后再推进下一张卡片

> 动效仅作用于按钮本体即可先满足“点击有动效”，后续可扩展为卡片飞出/淡出等更强反馈。

## 5. 主题状态与持久化

落点：`client/src/storage/appStorage.ts`

新增 key（与 `spec.md` 保持一致）：

- `ui.theme.mode`: `'scenery' | 'color'`

新增封装方法（示例命名）：

- `getThemeMode(): Promise<'scenery' | 'color'>`（默认 `scenery`）
- `setThemeMode(mode: 'scenery' | 'color'): Promise<void>`

Home 页读取主题 mode，并用于：

- 页面背景（风景/颜色）
- 卡片背景与局部配色（按设计稿映射）

## 6. SVG 导入支持（工程配置）

由于项目当前未见 `metro.config.js`，计划新增 SVG transformer 支持：

1. 安装依赖：`react-native-svg-transformer`
2. 新增 `client/metro.config.js`，基于 `expo/metro-config` 配置：
   - 将 `svg` 从 assetExts 移到 sourceExts
   - `babelTransformerPath` 指向 transformer

完成后可以直接：

- `import LikeIcon from '@/assets/images/home/like.svg'`

## 7. i18n 文案补齐（用于标题/无障碍）

建议新增 key（至少 `zh-CN/en`，其余语言可后续补齐）：

- `home.theme`（用于无障碍 label）
- `home.profile`（用于无障碍 label）
- `theme.title`、`theme.scenery`、`theme.color`
- `profile.title`、`profile.favorites`、`profile.widget`、`profile.dailyReminder`、`profile.privacy`、`profile.terms`、`profile.language`

> 原有 `home.like/home.dislike` 即使不再显示文字，也可保留用于 `accessibilityLabel` 或未来回退。

## 8. 实施步骤

1. 配置 SVG 导入（新增 transformer + `metro.config.js`）
2. 新增通用弹窗组件 `SheetModal`（遮罩、圆角、背景色 `#FAF3EC`、关闭交互、基础动效）
3. 新增 `ThemeModal` 与 `ProfileModal`（复用 `SheetModal`）
4. 在 `appStorage.ts` 新增主题 mode 读写方法
5. 改造 `home.tsx`：
   - 自绘顶部栏（右上角两个圆形 icon 按钮）
   - 接入主题 mode 影响背景
   - 底部喜欢/讨厌替换为 icon + 动效
6. 补齐 i18n key
7. 自测：
   - 主题切换后即时生效并可持久化
   - 个人主页弹窗打开/关闭体验一致
   - 喜欢/讨厌点击有动效且逻辑正常推进卡片

## 9. 验收标准

- 卡片页右上角两个 icon 按钮显示正确，点击热区合理
- 主题弹窗与个人主页弹窗：
  - 背景色 `#FAF3EC`
  - 遮罩/圆角/关闭交互一致
- 喜欢/讨厌按钮为 icon（`like.svg` / `hate.svg`）且点击有动效
- 主题选择被持久化，重启 App 后仍保持上次主题

