Files
2026-01-29 23:31:12 +08:00

170 lines
6.6 KiB
Markdown
Raw Permalink 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.
# 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若项目未引入则先不加把“打开弹窗”动作传给页面
本计划默认采用 **AHome 页自绘顶部栏)**,因为实现最直接、样式可控、无跨层状态传递。
### 4.2 主题弹窗(背景色 #FAF3EC
落点建议:
- `client/components/home/ThemeModal.tsx`
- `client/components/ui/SheetModal.tsx`(复用:遮罩、圆角容器、上滑/淡入动效、关闭逻辑)
交互:
- 点击主题按钮 → 打开弹窗
- 选择「风景 / 颜色」→ 立即写入主题 mode + 关闭(或保持打开并高亮选中,按设计稿)
- 点击遮罩 / 关闭按钮 → 关闭
视觉:
- 弹窗内容区背景:`#FAF3EC`
- 容器圆角与内边距按设计稿(默认 24 圆角、1620 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 后仍保持上次主题