# Card UI(任务清单) > 说明:本清单根据 `plan.md` 拆解,要求“可执行、可验收、可标记”。 > 标记规则:执行完成后将对应项从 `- [ ]` 改为 `- [x]`,并把“状态”改为 **已完成**;进行中改为 **进行中**;阻塞写明原因与解除条件。 ## 0. UI 参考(本次实现对齐) - **参考截图**:你提供的卡片页 + 主题弹窗 + 我的弹窗 - **弹窗内容区背景色**:`#FAF3EC` - **右上角按钮资源**:`client/assets/images/home/theme.svg`、`client/assets/images/home/my.svg` - **底部反应按钮资源**:`client/assets/images/home/like.svg`、`client/assets/images/home/hate.svg` - **交互约束**: - 弹窗为**底部上拉(Sheet)** - 关闭方式:**点 X 关闭**(不要求点遮罩关闭) - 顶部按钮使用**系统导航栏**(`headerRight`) - 主题切换最少影响:**页面背景** - 个人主页弹窗中的列表项:本期允许 **仅做占位** - 喜欢动效为**强反馈:心形填满**(按压回弹 + 填充变化) ## 1. 依赖与基础设施(SVG 可 import) - [x] **安装 `react-native-svg-transformer` 并新增 `client/metro.config.js`** - **状态**:已完成 - **原因**:让 `assets/images/home/*.svg` 支持 `import XxxIcon from '...svg'` 作为组件使用 - **命令**: ```bash cd client pnpm add react-native-svg-transformer ``` - **实现点**: - 新增 `client/metro.config.js`,基于 `expo/metro-config` 配置 `svg` transformer - **验收**: - 任一页面可成功渲染 `theme.svg`/`like.svg`(真机/模拟器均可) - `pnpm start` 正常启动,无 Metro 报错 ## 2. 本地存储:主题模式持久化 - [x] **在 `src/storage/appStorage.ts` 新增主题 mode key 与读写方法** - **状态**:已完成 - **Key**:`ui.theme.mode` - **类型**:`'scenery' | 'color'`(默认 `scenery`) - **新增 API(建议)**: - `getThemeMode(): Promise<'scenery' | 'color'>` - `setThemeMode(mode: 'scenery' | 'color'): Promise` - **验收**: - 代码中不散落硬编码 key - 切换主题后重启 App 仍保持上次选择 ## 3. 通用组件:底部上拉弹窗(Sheet)框架 - [x] **新增通用 `SheetModal` 组件(底部上拉 + 背景色 #FAF3EC + X 关闭)** - **状态**:已完成 - **建议路径**:`client/components/ui/SheetModal.tsx` - **要求**: - 遮罩存在(可拦截背景交互),但本期**不要求点遮罩关闭** - 内容区背景色固定为 `#FAF3EC` - 顶部提供右上/左上 **X 按钮**关闭(以设计稿为准) - 基础动效:上滑进入、下滑退出(或淡入淡出 + translateY) - **验收**: - 任意页面可打开/关闭该弹窗,不闪烁、不穿透点击 - iOS 安全区适配正常(底部不被 Home Indicator 遮挡) ## 4. 主题弹窗:风景 / 颜色 - [x] **实现 `ThemeModal`(复用 `SheetModal`)** - **状态**:已完成 - **建议路径**:`client/components/home/ThemeModal.tsx` - **内容**: - 标题:主题 - 选项:风景 / 颜色(含预览卡片) - 选中态:明显高亮(描边/阴影/勾选均可) - **交互**: - 点击选项:`setThemeMode(...)` 并立即生效(可关闭弹窗或保持打开,按设计稿) - 点 X:关闭 - **验收**: - 两种主题可切换 - 切换后 Home 页面背景立刻变化 ## 5. 个人主页弹窗:占位入口 - [x] **实现 `ProfileModal`(复用 `SheetModal`)** - **状态**:已完成 - **建议路径**:`client/components/home/ProfileModal.tsx` - **内容(按设计最小闭环)**: - 顶部:插画/头像 + 昵称(来自 `getUserProfile().name`,无则占位) - 快捷卡片:我的喜欢 / 小组件(小组件可占位) - 通用列表:每日提醒 / 隐私政策 / 使用条款 / 语言(本期均允许占位) - **交互**: - 点 X:关闭 - 列表项点击:占位反馈(例如 `Alert` 或轻提示),不崩溃即可 - **验收**: - 弹窗 UI 与 ThemeModal 同一套视觉(背景色/圆角/间距一致) - 点击各入口有明确反馈 ## 6. 卡片页头部:系统导航栏右上角两个 icon 按钮 - [x] **改造 `client/app/(app)/_layout.tsx`:`home` 的 `headerRight` 使用两个圆形 icon 按钮** - **状态**:已完成 - **要求**: - 两按钮水平排列、圆形浅色底、`hitSlop>=10` - 左:主题(`theme.svg`),右:我的(`my.svg`) - **事件传递方案(需要落地)**: - 实际落地:在 `home.tsx` 内通过 `navigation.setOptions()` 设置 `headerRight`,直接使用页面 state 打开 Theme/Profile 弹窗(避免跨层事件传递) - **验收**: - 右上角两个按钮展示正确 - 点击分别能打开对应弹窗 ## 7. 卡片页内容:喜欢/讨厌改为 icon + 强反馈动效 - [x] **改造 `client/app/(app)/home.tsx`:底部按钮从文字改为 icon** - **状态**:已完成 - **要求**: - 喜欢按钮使用 `like.svg` - 讨厌按钮使用 `hate.svg`(逻辑仍写入 reaction=`dislike`) - **验收**:两按钮 icon 显示清晰,点击逻辑仍正常推进下一张卡片 - [x] **实现“强反馈:心形填满”点击动效** - **状态**:已完成 - **范围**:至少作用于“喜欢”按钮 - **建议实现**: - `pressIn/pressOut`:按钮缩放回弹 - `onPress`:短促强调动效(scale 1 → 1.12 → 1) - “填满”效果:点击后切换到“填充版心形”(若当前资源仅描边,需要: - 新增一份 `like_filled.svg`(或在现有 SVG 上修改 fill/stroke),并保持风格一致 - 或用 `react-native-svg` 动态改 `fill`(可行但实现复杂) - **验收**: - 点击喜欢按钮能看到明显的“变填充 + 弹一下”反馈 - 动效结束后再推进下一张卡片(避免动画被切页吞掉) ## 8. 主题对 Home 背景的影响 - [x] **让主题 mode 影响 Home 页面背景** - **状态**:已完成 - **规则**: - `scenery`:使用风景主题背景(可先用现有米色/图片占位) - `color`:使用颜色主题背景(可先用淡粉色/纯色占位) - **验收**:切换主题后背景立即变化;返回/重进页面仍正确 ## 9. i18n(用于标题/无障碍/占位文案) - [x] **补齐本需求相关 i18n key(至少 zh-CN/en)** - **状态**:已完成 - **建议 key**: - `theme.title`、`theme.scenery`、`theme.color` - `profile.title`、`profile.favorites`、`profile.widget` - `profile.dailyReminder`、`profile.privacy`、`profile.terms`、`profile.language` - `home.theme`、`home.profile`(用于 `accessibilityLabel`) - **验收**:弹窗标题/选项/占位提示无硬编码长文案;切换语言可生效 ## 10. 自测与验收 - [ ] **主题弹窗流程自测** - **状态**:未开始 - **路径**:Home 右上角主题按钮 → 主题弹窗 → 切换风景/颜色 → 背景变化 → 重启后仍保持 - **验收**:符合 `spec.md` / `plan.md` / 本清单验收点 - [ ] **我的弹窗流程自测** - **状态**:未开始 - **路径**:Home 右上角我的按钮 → 个人主页弹窗 → 点 X 关闭 → 列表项点击占位反馈 - **验收**:弹窗不穿透、关闭稳定、占位反馈明确 - [ ] **喜欢/讨厌动效与逻辑自测** - **状态**:未开始 - **路径**:连续点击喜欢/讨厌 → 按钮动效可见 → 卡片索引推进 → 收藏/反应写入正常 - **验收**:无报错、不卡顿、动效不被切换吞掉