收口拼图首访输入与错误提示

将拼图首访提示词文本域迁移到 PlatformTextField

将拼图首访输入错误和登录保存错误迁移到 PlatformStatusMessage

补充拼图首访输入和错误提示公共组件断言

更新 PlatformUiKit 文档和 Hermes 决策记录
This commit is contained in:
2026-06-10 13:57:38 +08:00
parent 448b0697ee
commit 71690c3aaa
4 changed files with 162 additions and 8 deletions

View File

@@ -140,6 +140,7 @@
- 2026-06-10 追加NPC 交易详情里的装备位、即时使用和标签属性格使用 `PlatformSubpanel surface="dark" padding="row"`,使用效果提示使用 `PlatformStatusMessage surface="editorDark"`;物品详情弹窗只保留物品属性、效果和标签计算,不再手写 `rounded-lg border border-white/8 bg-black/20 px-3 py-2` 或 emerald 提示条 chrome。
- 2026-06-10 追加:新增 `PlatformDarkOptionCard` 承接 RPG 暗色弹窗 / 面板中的可选项按钮卡 selected / idle / hover / disabled chromeNPC 交易模式、交易物品行、赠礼候选、招募替换候选、角色素材工作室动作预览格和营地编组替换位按钮已迁移。业务组件只保留选中判断、tone、点击回调和卡片内容不再手写 `rounded-* border px-3 py-*``border-*-400/* bg-*-500/10``border-white/* bg-black/20 hover:border-white/15`
- 2026-06-10 追加:角色聊天弹窗的状态 / 总结卡使用 `PlatformSubpanel surface="dark"`,空聊天记录使用 `PlatformEmptyState surface="editorDark"`,建议回复按钮使用 `PlatformDarkOptionCard tone="sky"`;弹窗只保留角色状态、聊天记录和建议语义,不再手写这些暗色信息卡、空态或建议按钮 chrome。验证命令`npm run test -- src/components/CharacterChatModal.test.tsx src/components/common/PlatformStatusMessage.test.tsx src/components/common/PlatformSubpanel.test.tsx src/components/common/PlatformEmptyState.test.tsx src/components/common/PlatformDarkOptionCard.test.tsx`
- 2026-06-10 追加:拼图首访 onboarding 提示词文本域使用 `PlatformTextField surface="editorDark"`,输入错误和登录保存错误使用 `PlatformStatusMessage surface="editorDark"`onboarding 保留全屏沉浸壳层、琥珀主 CTA、登录 / 生成状态机和跳过行为,不再手写 textarea / 错误条 chrome。验证命令`npm run test -- src/components/platform-entry/PlatformEntryFlowShellImpl/PuzzleOnboardingView.test.tsx src/components/common/PlatformStatusMessage.test.tsx src/components/common/PlatformTextField.test.tsx`
- 2026-06-10 追加RPG 大编辑器本地 `SectionPanel` 适配到 `PlatformSubpanel surface="dark"`;可扮演角色背景故事 / 关系 / 技能 / 物品、世界基础设定等编辑分区只保留标题、subtitle、右侧动作和内容插槽不再由本地适配器手写外层暗色面板 chrome。验证命令`npm run test -- src/components/CustomWorldEntityEditorModal.test.tsx src/components/common/PlatformSubpanel.test.tsx -t "可扮演角色技能动作状态|supports dark compact subpanel cards"`
- 2026-06-10 验证补充RPG 大编辑器上传封面中提示收口到 `PlatformSubpanel surface="darkSky"` 后,补跑 `npm run test -- src/components/CustomWorldEntityEditorModal.test.tsx src/components/common/PlatformSubpanel.test.tsx -t "作品封面上传|tinted dark information panels"`
- 2026-06-10 追加RPG 角色形象参考图缩略框使用 `PlatformMediaFrame surface="editorDark"`;角色形象面板只保留参考图数组、上传 / 清空回调和状态文案,不再手写 `img + overflow-hidden + border` 缩略图 chrome。
@@ -293,6 +294,7 @@
- 2026-06-10 验证补充:上传预览横向已选素材条 soft row 子面板收口补跑 `npm run test -- src/components/common/PlatformSubpanel.test.tsx src/components/common/PlatformUploadPreviewCard.test.tsx`
- 2026-06-10 验证补充creation-agent 无 session / 加载提示块收口补跑 `npm run test -- src/components/common/PlatformSubpanel.test.tsx src/components/creation-agent/CreationAgentWorkspace.test.tsx`
- 2026-06-10 验证补充creation-agent 聊天空态和 composer 文本域收口后,补跑 `npm run test -- src/components/creation-agent/CreationAgentWorkspace.test.tsx src/components/common/PlatformEmptyState.test.tsx src/components/common/PlatformTextField.test.tsx`
- 2026-06-10 验证补充:拼图首访 onboarding 提示词文本域、输入错误和登录保存错误收口后,补跑 `npm run test -- src/components/platform-entry/PlatformEntryFlowShellImpl/PuzzleOnboardingView.test.tsx src/components/common/PlatformStatusMessage.test.tsx src/components/common/PlatformTextField.test.tsx`
- 2026-06-10 验证补充:拼图结果页空草稿提示块收口补跑 `npm run test -- src/components/common/PlatformSubpanel.test.tsx src/components/puzzle-result/PuzzleResultView.test.tsx`
- 2026-06-10 验证补充RPG 个人中心未登录提示子面板收口补跑 `npm run test -- src/components/common/PlatformSubpanel.test.tsx`,并对 `src/components/rpg-entry/RpgEntryHomeView.tsx` 执行 ESLint / typecheck游客态当前不暴露“我的”Tab不新增不可达业务断言。
- 2026-06-10 验证补充:拼图图库详情页封面轮播壳收口到 `PlatformSubpanel radius="xl" padding="none"` 后,补跑 `npm run test -- src/components/common/PlatformSubpanel.test.tsx src/components/puzzle-gallery/PuzzleGalleryDetailView.test.tsx`

View File

@@ -64,6 +64,7 @@
- `CopyFeedbackMessage`:接收 `state``copiedLabel``failedLabel`toast 或行内状态只展示成功 / 失败时使用,不在业务页手写三态分支。
- `PlatformStatusMessage`:接收 `tone="error" | "success" | "info" | "warning" | "neutral"``surface="light" | "tinted" | "platform" | "profile" | "editorDark"``size="xs" | "sm" | "md"``remapSurface``children``className`;根节点固定带 `platform-status-message` 稳定类名,业务测试可断言公共状态条接入。局部可覆盖圆角、外边距和网格布局,但状态色值、基础内边距和字号由 Module 统一控制。结果页、发布检查、素材生成面板和 creation-agent composer 错误条等需要复用旧 `platform-banner--danger / success / info / warning / neutral` token 外观时使用 `surface="platform"`;需要在局部 platform token 作用域内重映射 CSS 变量的提示条传 `remapSurface`,不在业务 JSX 手写 `platform-remap-surface platform-banner`。个人中心弹窗、认证入口、验证码提示、统一创作工作台和通用创作输入区需要 profile token 外观时使用 `surface="profile"`RPG 暗色编辑 / 运行面板内的普通状态提示使用 `surface="editorDark"`;背包故事档案 QA、NPC 叙事提示、角色聊天错误提示、营地编组战斗中提示、自定义选择弹窗错误 / 生成中提示等暗色状态条已迁移。旧 `platform-profile-error` / `platform-profile-success`、暗色手写 `border-*-300/15 bg-*-500/10 text-*-50/90``platform-banner--danger / success / info / warning / neutral` 不再作为业务 JSX 接口。
- `PlatformStatusMessage` 补充:大鱼吃小鱼结果页发布校验阻断项使用 `tone="warning" surface="platform" size="xs"`;结果页只保留阻断项裁剪和文案,不再手写 amber 文本列表。
- `PlatformStatusMessage` 补充:拼图首访 onboarding 的输入错误和登录保存错误使用 `surface="editorDark"`onboarding 只保留错误文案和条件渲染,不再手写暗色红色错误条。
- `PlatformRuntimeStatusToast`:接收 `tone="error" | "success" | "info" | "warning" | "neutral"``surface="light" | "dark" | "solid"``size="xs" | "sm" | "md"``shape="pill" | "rounded"``children``className`;根节点固定带 `platform-runtime-status-toast` 稳定类名,默认按 `tone` 写入 `role="alert/status"``aria-live`。它只承接运行态 HUD 中短错误、成功和反馈 chip 的圆角、字号、阴影、色值和可访问语义,具体浮层位置、玩法资产按钮、计分牌、蓄力提示、强品牌 primary 按钮仍由玩法 runtime 控制。跳一跳、拼图、敲木鱼、方洞和宝贝爱画运行态的短错误 / 成功 / 投放反馈已先迁移;后续同类短 toast 不再手写 `rounded-full bg-white/* text-*`、暗色 `border-rose/emerald bg-*/text-*` 或单玩法 `*-runtime-error-chip`
- `PlatformDarkOptionCard`:接收 `selected``tone="emerald" | "sky" | "rose" | "amber"``radius="sm" | "md" | "lg"``padding="sm" | "md" | "lg"``children``className` 和原生 button props根节点固定带 `platform-dark-option-card` 稳定类名,统一承接 RPG 暗色弹窗 / 面板中的 selected / idle / hover / disabled 可选项卡按钮外观。NPC 交易模式、交易物品行、赠礼候选、招募替换候选、角色素材工作室动作预览格、营地编组替换位按钮和角色聊天建议按钮已先迁移;业务页只保留选中判断、点击回调和内容布局,不再重复手写 `rounded-* border px-3 py-*``border-*-400/* bg-*-500/10``border-white/* bg-black/20 hover:border-white/15`
- `PlatformEmptyState`:接收 `surface="soft" | "dashed" | "subpanel" | "editorDark"``size="compact" | "panel" | "inline"``tone="base" | "soft"``children``className`;根节点固定带 `platform-empty-state` 稳定类名,业务测试可断言公共空态接入。`soft + compact` 用于公开广场、排行和作品架内的轻量空态,`soft + panel` 用于创作中心作品架整块空态,`dashed + panel` 用于素材选择、历史资源等弹窗的大面积空态或读取态,`subpanel + inline` 用于视觉小说 runtime、个人中心充值 / 任务等白底子面板内的无操作空态,`editorDark + compact/inline` 用于 RPG 大编辑器、实体详情弹窗、营地编组、角色聊天和运行态设置弹窗等暗色面板里的纯展示空态 / 禁用提示。组件只承接外观,不内置业务文案。
@@ -76,6 +77,7 @@
- `PlatformTextField` 补充:个人中心昵称弹窗输入框使用 `surface="editorDark" size="lg" density="roomy"`,业务组件保留外层原生 `label` / sr-only “新昵称”、`autoFocus``maxLength`、Enter 提交和保存状态;局部 class 只保留暗色弹窗里的 `bg-white/10`、文字色和焦点边框,不再手写 input chrome。
- `PlatformTextField` 补充:`PlatformTagEditor` 内部新增标签输入框使用 `density="compact" size="xs"` 复用同一输入 chrome标签编辑器只保留新增输入状态、解析、Enter / Escape 行为和按钮组合,不再手写输入框边框、白底、字号、焦点色或禁用态。
- `PlatformTextField` 补充creation-agent composer 文本域使用 `variant="textarea" size="md" density="compact"`工作台只保留受控值、禁用条件、Enter / Shift+Enter 行为和局部布局 class不再手写 textarea chrome。
- `PlatformTextField` 补充:拼图首访 onboarding 提示词文本域使用 `variant="textarea" surface="editorDark" density="roomy" size="lg"`onboarding 保留受控输入、生成 / 已生成禁用和沉浸式壳层,不再手写 textarea 基础 chrome。
- `PlatformFieldLabel`:接收 `variant="field" | "section" | "form" | "pill" | "accentPill"``children``className``field` 用于视觉小说等结果页的普通字段名,`section` 用于平台白底面板内小标题,`form` 用于创作工作台、通用创作输入面板和认证表单普通字段标题,`pill` / `accentPill` 用于汪汪声浪等工作台里的胶囊字段标题。业务页只传字段文案和必要的局部 class不再重复写 `text-xs font-bold text-[var(--platform-text-soft)]``text-xs font-bold tracking-[0.18em] text-[var(--platform-text-soft)]``mb-2 block text-sm font-black`、普通胶囊或 rose 强调胶囊 class。视觉小说结果页、抓大鹅结果页作品 / 封面 / 素材字段标题、方洞结果页主信息 / 形状 / 洞口 / 历史图片字段标题、拼图结果页关卡详情 / 发布弹窗字段标题、拼消消创作工作台作品标题 / 简介 / 主题词、跳一跳创作工作台主题、大鱼素材弹窗 prompt、RPG 发布弹窗发布检查 / 封面设置、汪汪声浪轻配置编辑器、宝贝识物工作台、通用创作图片输入面板主图 / 提示词标题,以及认证表单中的手机号 / 验证码 / 密码 / 邀请码标题已先迁移。认证和提示词字段继续保留外层原生 `label` 关联,不把可访问命名交给装饰性标题组件。
- `PlatformFieldLabel` 补充:个人中心玩过弹窗内的“可继续 / 玩过”分区标题使用 `variant="section"`;业务组件只传分区文案和 `mb-2 block` 局部布局,不再手写 `text-xs font-black text-zinc-500`
- `PlatformFieldLabel` 补充:个人中心邀请弹窗里的“邀请码 / 成功邀请”小标题使用 `variant="section"`;业务组件只保留必要的居中或深色文本局部 class不再手写同类小标题字体。
@@ -145,7 +147,7 @@
12. RPG 场景背景和作品封面生成结果未保存时,退出确认也使用 `UnifiedConfirmDialog`;像素风场景生成弹窗通过 `variant="pixel"` 适配视觉。
13. 公开作品详情或运行态深链失效时,由平台入口壳展示 `UnifiedConfirmDialog` 的“作品不可用”提示;用户确认后再回到首页,错误处理分支不再调用浏览器原生 `window.alert`
14. 带复杂内容的专用 Module 可以保留自己的布局,但复制反馈仍应复用 `useCopyFeedback`;如果有可点击复制按钮,优先复用 `CopyFeedbackButton`;如果只展示复制结果提示,优先复用 `CopyFeedbackMessage`
15. 白底平台弹窗、详情页、结果页、目录页、个人页、认证入口、统一创作工作台和通用创作输入区的基础错误 / 成功 / 信息 / 警告 / 中性状态提示逐步迁移到 `PlatformStatusMessage`RPG 结果页、拼图结果页、抓大鹅结果页、跳一跳结果页、敲木鱼结果页、拼消消结果页、宝贝识物结果页、方洞结果页、汪汪声浪结果页、视觉小说结果页、拼消消创作工作台、宝贝识物创作工作台、视觉小说创作工作台、汪汪声浪创作工作台、creative-agent 工作台、creation-agent operation banner、自定义世界实体目录和拼消消 runtime 白底错误条已使用 `surface="platform"` 承接发布检查、错误提示、进度提示、素材生成提示、资源未就绪提示和主线目标提示;个人中心、认证入口、统一创作工作台和创作输入区需要 profile token 外观时使用 `surface="profile"`RPG 暗色编辑 / 运行面板里的普通错误 / 成功 / 信息 / 警告 / 中性提示使用 `surface="editorDark"`,背包故事档案 QA 提示、NPC 交易 / 赠礼 / 招募叙事提示和角色聊天错误提示已先迁移。运行态里的短错误 / 成功 / 命中反馈 chip 使用 `PlatformRuntimeStatusToast`,位置和玩法强品牌 HUD 仍留在 runtime 壳层;深色半透明游戏内提示和强品牌样式可以暂保留专用布局,避免状态条组件过早承接游戏视觉。
15. 白底平台弹窗、详情页、结果页、目录页、个人页、认证入口、统一创作工作台和通用创作输入区的基础错误 / 成功 / 信息 / 警告 / 中性状态提示逐步迁移到 `PlatformStatusMessage`RPG 结果页、拼图结果页、抓大鹅结果页、跳一跳结果页、敲木鱼结果页、拼消消结果页、宝贝识物结果页、方洞结果页、汪汪声浪结果页、视觉小说结果页、拼消消创作工作台、宝贝识物创作工作台、视觉小说创作工作台、汪汪声浪创作工作台、creative-agent 工作台、creation-agent operation banner、自定义世界实体目录和拼消消 runtime 白底错误条已使用 `surface="platform"` 承接发布检查、错误提示、进度提示、素材生成提示、资源未就绪提示和主线目标提示;个人中心、认证入口、统一创作工作台和创作输入区需要 profile token 外观时使用 `surface="profile"`RPG 暗色编辑 / 运行面板和拼图首访 onboarding 里的普通错误 / 成功 / 信息 / 警告 / 中性提示使用 `surface="editorDark"`,背包故事档案 QA 提示、NPC 交易 / 赠礼 / 招募叙事提示和角色聊天错误提示已先迁移。运行态里的短错误 / 成功 / 命中反馈 chip 使用 `PlatformRuntimeStatusToast`,位置和玩法强品牌 HUD 仍留在 runtime 壳层;深色半透明游戏内提示和强品牌样式可以暂保留专用布局,避免状态条组件过早承接游戏视觉。
16. 正方形图片裁剪的初始居中、边界 clamp 和裁剪矩形类型统一从 `squareImageCropModel` 导入,避免头像裁剪、拼图参考图裁剪等业务页面依赖弹窗组件文件里的 helper。
17. 个人中心的账户充值、泥点账单、每日任务、兑换码、扫码、存档、玩过作品、邀请 / 社区、昵称修改、头像裁剪,以及平台筛选、创作图片预览、认证入口、邀请码弹窗、公开编号搜索结果弹窗、方洞结果页图片素材弹窗、视觉小说结果页资产 / 音频 / 编辑器弹窗、视觉小说 runtime 普通面板、creative-agent 模板确认弹窗、像素风 UnifiedModal 和自定义选择弹窗等圆形关闭按钮迁移到 `PlatformModalCloseButton`;后续新增弹窗关闭按钮先判断是否属于 `profile``profileCompact``floating``floatingPlain``platformIcon``pixel``editorDark` 七类,确有品牌化或运行态 HUD 语义时才保留专用按钮。
17.1. 平台弹窗 header 和普通工具栏里的 `platform-icon-button` 迁移到 `PlatformIconButton`历史图片选择弹窗、RPG 发布检查弹窗、creative-agent 侧边栏关闭 / 外观 / 设置入口、通用输入 Composer 上传 / 发送 / 移除参考图、creation-agent composer 上传文档 / 上传参考图、creation-agent 参考图移除、敲木鱼结果页新增主题标签入口、敲木鱼创作工作台功德词条删除入口、拼图结果页标签生成 / 标签新增 / 关卡详情关闭 / 发布弹窗关闭 / 删除关卡入口、视觉小说结果页素材选择 / 音频生成 / 保存草稿 / 运行配置入口、RPG 首页搜索结果清空入口、方洞结果页形状 / 洞口选项删除入口,以及抓大鹅结果页标签生成 / 标签新增 / 物品素材删除 / 参考图上传入口已先迁移。结果页内的普通平台弹窗关闭入口使用 `PlatformModalCloseButton variant="platformIcon"`;图标上传控件使用 `PlatformIconButton asChild="label"` 保留 label + file input 语义,不改成普通按钮;`PlatformIconButton` 的 label 模式会自动写入隐藏文本,保证内嵌 file input 仍能继承可访问名称。通用创作图片面板中覆盖在图片上的更换主图、移除主图、历史入口短标签按钮和提示词参考图上传入口,抓大鹅封面编辑中覆盖在封面图上的移除入口,以及敲木鱼创作工作台功德词条删除入口使用 `PlatformIconButton variant="surfaceFloating"`,不再手写白底圆形 / 短标签浮动按钮 chrome。运行态 HUD、带复制状态或需要专用交互禁用语义的图标按钮先保留专用布局等对应场景验证时再迁移。
@@ -153,7 +155,7 @@
17.3. RPG 大编辑器主壳层和紧凑对话壳层的右上角关闭入口迁移到 `PlatformModalCloseButton variant="platformIcon"`;暗色编辑器仍保留原 `platform-icon-button` 视觉 token但业务 JSX 不再手写 `button``aria-label` 和默认关闭图标。
18. RPG 首页、公开广场、排行、作品架、个人中心充值 / 任务弹窗、视觉小说 runtime 普通白底面板、历史素材选择弹窗、视觉小说上传资产弹窗本地上传占位、自定义世界实体目录搜索无结果、大鱼吃小鱼结果页缺草稿提示、RPG 大编辑器纯展示暗色列表、背景故事空档案和 RPG 运行态设置保存禁用提示中的无操作空态 / 轻量读取态迁移到 `PlatformEmptyState`;后续空态如果包含 CTA、插画、复杂列表恢复动作或玩法 HUD再保留专用布局。
18.1. 历史图片 / 历史素材 / 可引用素材选择迁移到 `PlatformAssetPickerCard``PlatformAssetPickerGrid`拼图历史图片弹窗、方洞历史生成、视觉小说历史素材选择器、RPG 大编辑器历史素材弹窗和抓大鹅封面编辑可引用素材网格已先迁移。后续素材选择只传素材数组、`imageSrc`、主副文案、可访问名称、surface、选中判断和选择回调不再在业务页重复缩略图、边框、选中 ring、禁用态、`ResolvedAssetImage` 壳层、虚线读取 / 空态和网格 JSX。
18.2. 平台白底圆角输入框和文本域迁移到 `PlatformTextField surface="platform"`RPG 暗色弹窗 / 运行面板里的普通输入框、文本域和下拉框迁移到 `PlatformTextField surface="editorDark"` / `PlatformSelectField surface="editorDark"`;抓大鹅结果页作品名称 / 描述、封面描述、素材名称、批量新增 / 批量重生成物品名称,方洞结果页游戏名称、标签、简介、题材主题、反差规则、背景提示、形状数量、形状 / 洞口名称、形状目标洞口和图片提示词,拼图结果页作品名称 / 描述、关卡名称和智能修订输入,敲木鱼结果页作品标题 / 简介,视觉小说结果页的音乐生成、作品信息、开场、运行配置、角色、场景、阶段和世界观普通文本 / 下拉字段,以及视觉小说 / 抓大鹅 / 汪汪声浪 / 宝贝识物 / 拼消消 / 跳一跳创作工作台普通输入字段、敲木鱼创作工作台功德词条输入、creative-agent 模板确认调整弹层关卡数输入已先迁移。通用输入 Composer、通用创作图片输入面板的提示词文本域、自定义世界实体目录搜索框、认证验证码答案输入、短信 / 密码登录、重置密码、绑定手机号、邀请码、账号安全表单字段、个人中心兑换码 / 邀请码输入、自定义选择弹窗角色名字 / 背景补充 / 生成模式 / 世界描述角色聊天草稿也使用 `PlatformTextField` / `PlatformSelectField`;浮动胶囊 Composer 可继续由 `.creative-agent-composer--floating textarea` 覆盖尺寸和背景,图片输入面板可通过局部 class 保留高度与浮动上传按钮避让,实体目录搜索框可通过局部 class 保留紧凑圆角和底色,验证码答案输入和认证表单字段可通过局部 class 保留表单高度、横向验证码按钮布局和原生 `label` 关联,个人中心兑换码 / 邀请码输入通过局部 class 保留大写和居中,暗色聊天草稿可通过局部 class 保留 `bg-black/25`,不在业务 JSX 中手写 textarea / input / select chrome。默认密度用于结果页主表单`density="compact"` 用于选项卡片、工具条或认证提示内的紧凑字段,`density="roomy"` 用于宽内边距文本域、关卡详情字段或暗色弹窗主文本域;默认 `tone="warm"`,玩法需要保留调性焦点色时使用 `tone="rose"``tone="emerald"``tone="sky"`,不要在业务 JSX 中重复写 `focus:border-* focus:ring-*`。后续结果页、工作台、目录工具条、认证提示、认证表单、个人中心轻量表单或 RPG 暗色弹窗内的普通文本输入 / 下拉框只传受控值、事件、可访问名称、占位符、选项和局部布局 class不再重复基础边框、背景、内边距、字号、禁用态和焦点色。
18.2. 平台白底圆角输入框和文本域迁移到 `PlatformTextField surface="platform"`RPG 暗色弹窗 / 运行面板里的普通输入框、文本域和下拉框迁移到 `PlatformTextField surface="editorDark"` / `PlatformSelectField surface="editorDark"`;抓大鹅结果页作品名称 / 描述、封面描述、素材名称、批量新增 / 批量重生成物品名称,方洞结果页游戏名称、标签、简介、题材主题、反差规则、背景提示、形状数量、形状 / 洞口名称、形状目标洞口和图片提示词,拼图结果页作品名称 / 描述、关卡名称和智能修订输入,敲木鱼结果页作品标题 / 简介,视觉小说结果页的音乐生成、作品信息、开场、运行配置、角色、场景、阶段和世界观普通文本 / 下拉字段,以及视觉小说 / 抓大鹅 / 汪汪声浪 / 宝贝识物 / 拼消消 / 跳一跳创作工作台普通输入字段、敲木鱼创作工作台功德词条输入、creative-agent 模板确认调整弹层关卡数输入已先迁移。通用输入 Composer、通用创作图片输入面板的提示词文本域、自定义世界实体目录搜索框、认证验证码答案输入、短信 / 密码登录、重置密码、绑定手机号、邀请码、账号安全表单字段、个人中心兑换码 / 邀请码输入、自定义选择弹窗角色名字 / 背景补充 / 生成模式 / 世界描述角色聊天草稿和拼图首访 onboarding 提示词文本域也使用 `PlatformTextField` / `PlatformSelectField`;浮动胶囊 Composer 可继续由 `.creative-agent-composer--floating textarea` 覆盖尺寸和背景,图片输入面板可通过局部 class 保留高度与浮动上传按钮避让,实体目录搜索框可通过局部 class 保留紧凑圆角和底色,验证码答案输入和认证表单字段可通过局部 class 保留表单高度、横向验证码按钮布局和原生 `label` 关联,个人中心兑换码 / 邀请码输入通过局部 class 保留大写和居中,暗色聊天草稿和首访提示词文本域可通过局部 class 保留沉浸式底色 / 高度,不在业务 JSX 中手写 textarea / input / select chrome。默认密度用于结果页主表单`density="compact"` 用于选项卡片、工具条或认证提示内的紧凑字段,`density="roomy"` 用于宽内边距文本域、关卡详情字段、首访提示词文本域或暗色弹窗主文本域;默认 `tone="warm"`,玩法需要保留调性焦点色时使用 `tone="rose"``tone="emerald"``tone="sky"`,不要在业务 JSX 中重复写 `focus:border-* focus:ring-*`。后续结果页、工作台、目录工具条、认证提示、认证表单、个人中心轻量表单、首访页或 RPG 暗色弹窗内的普通文本输入 / 下拉框只传受控值、事件、可访问名称、占位符、选项和局部布局 class不再重复基础边框、背景、内边距、字号、禁用态和焦点色。
18.2.1. 个人中心昵称弹窗输入框迁移到 `PlatformTextField surface="editorDark"`;昵称状态机、校验、保存和弹窗壳层不随输入框 chrome 收口改动。
18.3. 平台字段标签迁移到 `PlatformFieldLabel`;视觉小说结果页、抓大鹅结果页作品 / 封面 / 素材字段标题、方洞结果页主信息 / 形状 / 洞口 / 历史图片字段标题、拼图结果页关卡详情 / 发布弹窗字段标题、拼消消创作工作台作品标题 / 简介 / 主题词、跳一跳创作工作台主题、大鱼素材弹窗 prompt、RPG 发布弹窗发布检查 / 封面设置、汪汪声浪轻配置编辑器、宝贝识物工作台、通用创作图片输入面板主图 / 提示词标题,以及认证登录 / 绑定 / 邀请码 / 账号安全表单标题已先迁移。后续结果页、编辑弹窗、工作台、通用创作输入面板或认证表单中只表达字段名称的小标题,优先选择 `field` / `section` / `form` / `pill` / `accentPill`,不要在业务 JSX 中重复拼字段标题 class认证表单和提示词字段保留外层原生 `label`,带品牌化插画、运行态 HUD 或复杂步骤标题时可暂保留专用标题。
18.3.1. 个人中心存档 / 玩过弹窗里的简单空态、分区标题和已玩作品白底按钮卡分别迁移到 `PlatformEmptyState``PlatformFieldLabel``PlatformSubpanel``SaveArchiveCard` 带图片遮罩和加载视觉,仍保留专用实现,后续需要单独视觉验收后再决定是否收口。

View File

@@ -0,0 +1,132 @@
/* @vitest-environment jsdom */
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
import { expect, test, vi } from 'vitest';
import {
PuzzleOnboardingLoginOverlay,
PuzzleOnboardingView,
type PuzzleOnboardingPhase,
} from './PuzzleOnboardingView';
function renderOnboarding({
prompt = '月亮糖果工厂',
phase = 'input',
error = null,
onPromptChange = vi.fn(),
onSubmit = vi.fn(),
onSkip = vi.fn(),
}: {
prompt?: string;
phase?: PuzzleOnboardingPhase;
error?: string | null;
onPromptChange?: (value: string) => void;
onSubmit?: () => void;
onSkip?: () => void;
} = {}) {
render(
<PuzzleOnboardingView
prompt={prompt}
phase={phase}
error={error}
copy="把梦做成拼图"
onPromptChange={onPromptChange}
onSubmit={onSubmit}
onSkip={onSkip}
/>,
);
return { onPromptChange, onSubmit, onSkip };
}
test('PuzzleOnboardingView uses shared dark textarea and error status chrome', () => {
const { onPromptChange } = renderOnboarding({
error: '拼图生成失败',
});
const textarea = screen.getByPlaceholderText('把你的梦讲给我听吧');
fireEvent.change(textarea, { target: { value: '一座会唱歌的城堡' } });
expect(textarea.tagName).toBe('TEXTAREA');
expect(textarea.className).toContain('platform-text-field--editor-dark');
expect(textarea.className).toContain('min-h-32');
expect(onPromptChange).toHaveBeenCalledWith('一座会唱歌的城堡');
expect(screen.getByText('拼图生成失败').className).toContain(
'platform-status-message',
);
expect(screen.getByText('拼图生成失败').className).toContain(
'border-rose-300/15',
);
});
test('PuzzleOnboardingView preserves submit, skip, and disabled phase behavior', () => {
const { onSubmit, onSkip } = renderOnboarding();
fireEvent.click(screen.getByRole('button', { name: '生成' }));
fireEvent.click(screen.getByRole('button', { name: '跳过' }));
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSkip).toHaveBeenCalledTimes(1);
cleanup();
renderOnboarding({ prompt: '', phase: 'input' });
expect(screen.getByRole('button', { name: '生成' })).toHaveProperty(
'disabled',
true,
);
cleanup();
renderOnboarding({ phase: 'generating' });
expect(screen.getByPlaceholderText('把你的梦讲给我听吧')).toHaveProperty(
'disabled',
true,
);
expect(screen.getByRole('button', { name: '跳过' })).toHaveProperty(
'disabled',
true,
);
cleanup();
renderOnboarding({ phase: 'generated' });
expect(screen.getByPlaceholderText('把你的梦讲给我听吧')).toHaveProperty(
'disabled',
true,
);
expect(screen.getByRole('button', { name: '生成' })).toHaveProperty(
'disabled',
true,
);
});
test('PuzzleOnboardingLoginOverlay uses shared error status and keeps login action', () => {
const onLogin = vi.fn();
const { rerender } = render(
<PuzzleOnboardingLoginOverlay
isSaving={false}
error="保存首访拼图失败"
copy="登录后保存你的拼图"
onLogin={onLogin}
/>,
);
fireEvent.click(screen.getByRole('button', { name: '注册账号 / 登录' }));
expect(onLogin).toHaveBeenCalledTimes(1);
expect(screen.getByText('保存首访拼图失败').className).toContain(
'platform-status-message',
);
rerender(
<PuzzleOnboardingLoginOverlay
isSaving
error={null}
copy="登录后保存你的拼图"
onLogin={onLogin}
/>,
);
expect(screen.getByRole('button', { name: '注册账号 / 登录' })).toHaveProperty(
'disabled',
true,
);
});

View File

@@ -1,5 +1,8 @@
import { Loader2, Sparkles } from 'lucide-react';
import { PlatformStatusMessage } from '../../common/PlatformStatusMessage';
import { PlatformTextField } from '../../common/PlatformTextField';
export type PuzzleOnboardingPhase = 'input' | 'generating' | 'generated';
type PuzzleOnboardingViewProps = {
@@ -54,13 +57,18 @@ export function PuzzleOnboardingView({
onSubmit();
}}
>
<textarea
<PlatformTextField
variant="textarea"
surface="editorDark"
tone="warm"
density="roomy"
size="lg"
value={prompt}
disabled={isGenerating || isGenerated}
onChange={(event) => onPromptChange(event.target.value)}
placeholder="把你的梦讲给我听吧"
rows={4}
className="min-h-32 w-full resize-none rounded-[1.25rem] border border-white/14 bg-black/28 px-4 py-4 text-base font-semibold leading-7 text-white shadow-[0_18px_50px_rgba(0,0,0,0.24)] outline-none backdrop-blur placeholder:text-white/42 focus:border-amber-200/70 focus:ring-2 focus:ring-amber-200/20 disabled:opacity-70"
className="min-h-32 rounded-[1.25rem] border-white/14 bg-black/28 py-4 leading-7 shadow-[0_18px_50px_rgba(0,0,0,0.24)] backdrop-blur placeholder:text-white/42 focus:border-amber-200/70 focus:ring-2 focus:ring-amber-200/20 disabled:opacity-70"
/>
<button
type="submit"
@@ -78,9 +86,14 @@ export function PuzzleOnboardingView({
</button>
</form>
{error ? (
<div className="w-full rounded-[1rem] border border-red-300/30 bg-red-500/14 px-4 py-3 text-sm font-semibold text-red-50">
<PlatformStatusMessage
tone="error"
surface="editorDark"
size="md"
className="w-full font-semibold"
>
{error}
</div>
</PlatformStatusMessage>
) : null}
</section>
</div>
@@ -127,9 +140,14 @@ export function PuzzleOnboardingLoginOverlay({
)}
</button>
{error ? (
<div className="w-full rounded-[1rem] border border-red-300/30 bg-red-500/14 px-4 py-3 text-sm font-semibold text-red-50">
<PlatformStatusMessage
tone="error"
surface="editorDark"
size="md"
className="w-full font-semibold"
>
{error}
</div>
</PlatformStatusMessage>
) : null}
</section>
</div>