- 5 个解码阈值叙事里程碑(ms_5/12/25/40/60)+ 全屏碎片释放叠层 - loreLayer 已读标记(readLoreLayers + 点击文本标记 + 已读/未读视觉区分) - idleProjectHistory 详情展开(倒序最近 5 条 + 相对时间) - 新建 format.ts formatRelativeTime 工具函数 - 移动端 375px 适配审计(4 组件字号 9→10px + flex-wrap + 响应式 padding) - 严格 4 色全息,lint 零错误,agent-browser 端到端验证通过
90 lines
7.8 KiB
Markdown
Executable File
90 lines
7.8 KiB
Markdown
Executable File
---
|
||
Task ID: 2-b
|
||
Agent: full-stack-developer
|
||
Task: v0.16 完善 — loreLayer 已读标记 + idleProjectHistory 详情展开 + 移动端 375px 适配审计
|
||
|
||
Work Log:
|
||
- 必读上下文:worklog v0.15-release 段 + Codex.tsx(v0.15 loreLayers 分层渲染)+ StatsPanel.tsx(v0.15 抽出独立组件)+ types.ts GameState + config.ts FRAGMENTS/loreLayers/isLoreLayerUnlocked + gameStore.ts(actions + persist migrate)+ IdleOperationsPanel.tsx + BeaconPanel.tsx + ExpeditionPanel.tsx
|
||
- 子任务 1:loreLayer 已读标记
|
||
- 新建 `src/lib/game/format.ts` 导出 `formatRelativeTime(ts)` 工具函数(<60s "刚刚" / <60m "X 分钟前" / <24h "X 小时前" / <7d "X 天前" / 否则具体日期)
|
||
- `types.ts`:GameState 接口新增 `readLoreLayers: string[]`(位置:v0.14 idle 字段之后、元字段之前,注释标 v0.16 loreLayer 已读)
|
||
- `engine.ts`:
|
||
* `createInitialState` 末尾加 `readLoreLayers: []`(在 idleStats 之后)
|
||
* `performPrestige` 返回对象加 `readLoreLayers: Array.isArray(state.readLoreLayers) ? state.readLoreLayers : []`(跨周目永久保留,与 idle 永久字段同一区域)
|
||
- `gameStore.ts`:
|
||
* GameActions 接口加 `markLoreLayerRead: (fragmentId: string, layer: 1 | 2) => void`(在 tickIdleProjects 之后)
|
||
* 实现该 action:构造 key `${fragmentId}_L${layer}`,已存在则 no-op,否则 set 新数组
|
||
* persist migrate 函数末尾加 `readLoreLayers: Array.isArray(s.readLoreLayers) ? s.readLoreLayers : []`(不改 version,仍是 1)
|
||
- `Codex.tsx`:
|
||
* useShallow 订阅新增 `readLoreLayers` 与 `markLoreLayerRead`
|
||
* LoreLayerBlock 接收 `isRead` + `onMarkRead` props:
|
||
- 已读:层标题旁加 muted "✓ 已读" 标记 + 边框从 amber/fuchsia 高亮降级为 `border-white/10`
|
||
- 未读但已解锁:保持 v0.15 高亮 + 标题旁加 `animate-pulse` 脉冲小圆点 + "新" 字提示
|
||
- 文本区域包成 `<button>` 元素,点击调用 `onMarkRead`(自然交互,不另设按钮)
|
||
- 未读时下方加一行 muted "▸ 点击文本标记已读" 引导文字
|
||
* 列表卡片标题旁小圆点:未读时 `animate-pulse` + glow,已读时 `bg-*-400/30` 静态
|
||
* 顶部统计从单行"深层叙事 X/Y 已解锁"扩展为两行(移动端 stack / 桌面并排):深层叙事 X/Y 已解锁 + 已读 A/B(A=已读数,B=已解锁层数)
|
||
* 弹层 padding 从 `p-5` 改 `p-4 sm:p-5`,标题 `text-lg` 改 `text-base sm:text-lg`,外层 backdrop padding 从 `p-4` 改 `p-3 sm:p-4`(375px 适配)
|
||
|
||
- 子任务 2:idleProjectHistory 详情展开
|
||
- `StatsPanel.tsx`:
|
||
* useShallow 订阅新增 `idleProjectHistory` 数组与 `idleProjectSlots`(用于详情中潜在"进行中"状态参考)
|
||
* 删除原"放置工程历史 N 条"的简单行,改为 `col-span-2` 可展开按钮:
|
||
- 左侧 label + "(最近 5 条可展开)" 提示(仅 historyLen > 0 时显示)
|
||
- 右侧 "N 条" + ChevronDown/ChevronUp 图标(lucide-react)
|
||
* 展开后渲染 `col-span-2` 卡片:
|
||
- 空历史 → "暂无放置工程完成记录 · 前往「放置」标签派遣工程"
|
||
- 非空 → 倒序最近 5 条:每行 = 工程图标 + 工程名(truncate)+ 相对时间(formatRelativeTime)
|
||
- 最近一条用 `bg-fuchsia-500/5` 高亮
|
||
- 历史超 5 条时底部加 "仅展示最近 5 条 · 共 N 条历史" 提示
|
||
* 展开状态用本地 `useState<boolean>`
|
||
* useMemo 派生 `recentHistory`(避免每次渲染重切)
|
||
|
||
- 子任务 3:移动端 375px 适配审计
|
||
- 审计范围:Codex / IdleOperationsPanel / StatsPanel / BeaconPanel / ExpeditionPanel
|
||
- 修复点:
|
||
* `IdleOperationsPanel.tsx`:所有 `text-[9px]` → `text-[10px]`(11 处,符合"移动端字号最小 10px"规范)
|
||
* `BeaconPanel.tsx`:所有 `text-[9px]` → `text-[10px]`(7 处);信标链底部统计行 `flex items-center justify-between gap-2` → `flex flex-wrap items-center justify-between gap-x-2 gap-y-1`(防 3 组数据在 375px 溢出)
|
||
* `Codex.tsx`:弹层 padding + 标题字号响应式(见子任务 1);顶部统计区 `flex flex-col sm:flex-row`(移动端纵向堆叠)
|
||
* `StatsPanel.tsx`:detail 区 `text-[9px]` → `text-[10px]`(2 处)
|
||
- 审计通过(无需改):
|
||
* `ExpeditionPanel.tsx`:节点路径已用 `overflow-x-auto` 自适应窄屏;事件卡 p-3 padding 合理;按钮组 `flex-1` + abort 收起;能量条文字 `text-[10px]` 已达标;路径节点 `h-9 w-9` 36px 足够小且可横向滚动
|
||
* `BeaconPanel.tsx`:4 个里程碑节点 `w-12 h-12`(48px)× 4 = 192px + flex-1 分布,375px 下可容纳;日/周挑战卡 padding p-3 合理;周挑战+信标链已用 `grid-cols-1 lg:grid-cols-2` 移动单列
|
||
* `IdleOperationsPanel.tsx`:4 个 section 已用 `grid-cols-1 sm:grid-cols-N` / `grid-cols-2 sm:grid-cols-3` 响应式降级;DispatchCard 槽位按钮 `h-5 w-7` × 3 在单列布局下不溢出
|
||
* `Codex.tsx` 列表 `grid-cols-2 gap-2`:每卡片约 165px 宽,aspect-[4/3] + p-2 + text-[11px]/text-[9px](已升 text-[10px])在 375px 下可读
|
||
|
||
- 严格 4 色全息:emerald / rose / amber / fuchsia,未引入 blue / indigo
|
||
- useShallow:所有 store 订阅用 useShallow(Codex / StatsPanel 均已用)
|
||
- 持久化兼容:persist version 仍为 1,新字段 `readLoreLayers` 靠 migrate 兜底,旧存档加载时自动补 `[]`
|
||
- 与子代理 A 文件边界:types.ts/engine.ts/gameStore.ts 三个共享文件,A 的 `triggeredMilestones` / `pendingMilestone` / `dismissMilestone` 字段已落地,与本子代理的 `readLoreLayers` / `markLoreLayerRead` 完全无冲突(不同字段、不同 action、不同 migrate 行)
|
||
|
||
Stage Summary:
|
||
- ✅ 子任务 1:loreLayer 已读标记完整实现
|
||
- 类型 + store + UI 三层联动;点击层文本即可标记已读
|
||
- 视觉区分:已读 = muted "✓ 已读" + 边框降级为 border-white/10;未读 = 高亮 + 脉冲小圆点 + "新" 字
|
||
- 顶部统计新增"已读 A/B"行(A=已读数 / B=已解锁层数)
|
||
- 跨周目永久保留(performPrestige 不重置)
|
||
- ✅ 子任务 2:idleProjectHistory 详情展开完整实现
|
||
- "放置工程历史" 行可点击展开/收起
|
||
- 展开后显示最近 5 条倒序历史(图标 + 工程名 + 相对时间)
|
||
- 空态友好提示,超 5 条底部加"仅展示最近 5 条"说明
|
||
- ✅ 子任务 3:移动端 375px 适配审计完成
|
||
- 审 5 个组件,修 4 个(Codex / IdleOps / StatsPanel / Beacon),ExpeditionPanel 无需改
|
||
- 主要修复:text-[9px] → text-[10px](共 20 处,符合"移动端字号最小 10px"规范)
|
||
- 信标链底部统计加 flex-wrap 防 3 组数据溢出
|
||
- Codex 弹层 padding + 标题字号响应式
|
||
- Codex 顶部统计区移动端纵向堆叠
|
||
- ✅ 新建文件:`/home/z/my-project/src/lib/game/format.ts`
|
||
- ✅ 修改文件清单(绝对路径):
|
||
- `/home/z/my-project/src/lib/game/types.ts`(+readLoreLayers 字段)
|
||
- `/home/z/my-project/src/lib/game/engine.ts`(createInitialState 默认 + performPrestige 保留)
|
||
- `/home/z/my-project/src/store/gameStore.ts`(GameActions 签名 + action 实现 + migrate 补全)
|
||
- `/home/z/my-project/src/components/game/Codex.tsx`(已读标记 + 点击逻辑 + 顶部统计 + 弹层响应式)
|
||
- `/home/z/my-project/src/components/game/StatsPanel.tsx`(idleHistory 展开 + 相对时间 + 字号升级)
|
||
- `/home/z/my-project/src/components/game/IdleOperationsPanel.tsx`(字号 9→10px 升级)
|
||
- `/home/z/my-project/src/components/game/BeaconPanel.tsx`(字号 9→10px 升级 + 信标链底部 flex-wrap)
|
||
- ✅ bun run lint 零错误零警告
|
||
- ✅ HTTP 200,dev.log 无运行时错误(compile 11ms / render 33ms)
|
||
- ✅ 与子代理 A 文件边界完全无冲突(不同字段/action/migrate 行)
|
||
- ⚠️ 未做 agent-browser 端到端验证(按工单由主控完成)
|