收口创作代理聊天空态与输入框

将 creation-agent 聊天空态迁移到 PlatformEmptyState

将 creation-agent composer 文本域迁移到 PlatformTextField

补充空态输入框样式和键盘提交语义测试

更新 PlatformUiKit 文档和 Hermes 决策记录
This commit is contained in:
2026-06-10 13:22:58 +08:00
parent e22cb1d06b
commit da8f2e3624
4 changed files with 66 additions and 4 deletions

View File

@@ -214,6 +214,7 @@
- 2026-06-10 追加:个人中心充值弹窗的“暂无可购买套餐”和每日任务弹窗的“暂无任务”使用 `PlatformEmptyState surface="subpanel" size="inline"`;业务组件只保留数据分支,不再手写 `platform-subpanel rounded-2xl px-4 py-8` 空态 chrome。
- 2026-06-10 追加:`PlatformEmptyState` 根节点固定带 `platform-empty-state` 类名,并支持 `surface="editorDark"` 承接 RPG 大编辑器和运行态弹窗 / 面板里的暗色虚线纯展示空态;角色槽位、可选角色、关系、技能、物品、交易空列表、赠礼空列表、招募替换空列表、奖励物品空态、任务日志空态、运行态设置保存禁用提示和营地编组空队列只保留业务文案,不再重复拼 `rounded-2xl border border-dashed border-white/12 bg-black/20 px-4 py-4 text-sm text-zinc-500``rounded-xl border border-dashed border-white/10 bg-black/20 px-4 py-6 text-sm text-zinc-500``rounded-xl border border-dashed border-white/10 bg-black/20 px-3 py-4 text-center text-xs text-zinc-500`
- 2026-06-09 追加:自定义世界实体目录搜索框迁移到 `PlatformTextField density="compact"`,搜索无结果空态迁移到 `PlatformEmptyState surface="dashed"`;目录只保留搜索值、占位符和过滤语义,不再直接拼 `platform-subpanel rounded-2xl` 输入壳或虚线空态。
- 2026-06-10 追加creation-agent 聊天区“暂无消息”迁移到 `PlatformEmptyState surface="subpanel" size="compact"`composer 文本域迁移到 `PlatformTextField variant="textarea" size="md" density="compact"`工作台保留消息列表滚动、受控输入、禁用条件、Enter 提交和 Shift+Enter 换行语义,不再手写空态和 textarea chrome。
- 2026-06-09 追加:视觉小说 runtime 普通白底面板里的保存主按钮和历史重生成行内动作使用 `PlatformActionButton surface="platform"`;保存使用默认主动作,行内重生成使用 `tone="secondary" size="xs" shape="pill"`,业务页只保留图标、禁用条件和回调。
- 影响范围:`src/components/common/UnifiedConfirmDialog.tsx``src/components/common/useCopyFeedback.ts``src/components/common/CopyFeedbackButton.tsx``src/components/common/CopyCodeButton.tsx``src/components/common/CopyFeedbackMessage.tsx``src/components/common/PlatformStatusMessage.tsx``src/components/common/PlatformEmptyState.tsx``src/components/common/PlatformActionButton.tsx``src/components/common/platformActionButtonModel.ts``src/components/common/PlatformIconButton.tsx``src/components/common/PlatformUploadTile.tsx``src/components/common/PlatformUploadPreviewCard.tsx``src/components/common/PlatformMediaFrame.tsx``src/components/common/PlatformModalCloseButton.tsx`、平台入口壳、公共错误 / 完成 / 分享弹窗、公开详情页、大鱼 runtime / result、账号个人资料区、自定义世界实体目录、RPG 结果页重新生成确认、RPG / 拼图 / 抓大鹅 / 跳一跳 / 敲木鱼 / 拼消消 / 宝贝识物 / 方洞 / 汪汪声浪 / 视觉小说结果页普通按钮和状态提示、历史图片选择弹窗 / RPG 发布检查弹窗 / creative-agent 侧边栏 / creation-agent 参考图 / 敲木鱼结果页 / 拼图结果页普通图标按钮、方洞结果页图片素材弹窗关闭按钮、视觉小说结果页资产 / 音频 / 编辑器弹窗和 runtime 普通面板关闭按钮、统一创作页壳层、拼图创作工作台、拼消消创作工作台、宝贝识物创作工作台、视觉小说创作工作台、汪汪声浪创作工作台、creation-agent 推荐回复、creative-agent 工作台、creative-agent 模板确认弹窗、自定义世界实体目录小动作和状态提示、创作中心错误重试、反馈页 header 返回、认证入口 / 邀请码弹窗关闭按钮、通用生成页重试 / 中断动作、RPG 详情页删除确认、RPG 角色素材工作室泥点确认、RPG 场景编辑器阻断提示、RPG 角色背景章节阻断提示、RPG 编辑器未保存关闭确认、RPG 场景背景 / 作品封面生成退出确认、公开作品深链失效恢复、账户充值 / 泥点账单 / 每日任务 / 兑换码 / 扫码 / 存档 / 玩过作品等个人中心弹窗、RPG 首页 / 公开广场 / 作品架和历史素材选择弹窗空态、个人中心充值 / 任务 / 兑换 / 邀请 / 支付结果弹窗主动作按钮、RPG 作品详情和生成结果恢复面板平台动作按钮、法律信息弹窗 footer、通用创作图片 / 音频输入面板动作按钮和上传 label、统一创作工作台返回 / 生成按钮和错误提示、短信登录 / 密码登录 / 绑定手机号认证表单动作按钮和状态提示、账号安全弹窗动作按钮和状态提示、验证码提示、邀请码弹窗提交按钮和错误提示、错误 / 完成 / 分享弹窗复制按钮外观、结果页 / 工作台后续简单弹窗迁移。
- 验证方式:`npm run test -- src/components/common/UnifiedConfirmDialog.test.tsx src/components/common/useCopyFeedback.test.tsx src/components/common/CopyFeedbackButton.test.tsx src/components/common/CopyCodeButton.test.tsx src/components/common/CopyFeedbackMessage.test.tsx src/components/common/PlatformStatusMessage.test.tsx src/components/common/PlatformEmptyState.test.tsx src/components/common/PlatformActionButton.test.tsx src/components/common/platformActionButtonModel.test.ts src/components/common/PlatformIconButton.test.tsx src/components/common/PlatformUploadTile.test.tsx src/components/common/PlatformUploadPreviewCard.test.tsx src/components/common/PlatformModalCloseButton.test.tsx`,迁移页面时补跑对应页面交互测试;实体目录删除确认、角色背景章节阻断与场景编辑器提示补跑 `npm run test -- src/components/CustomWorldEntityEditorModal.test.tsx`;公开作品深链失效恢复补跑 `npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "direct missing public work detail"`RPG 结果页重新生成确认补跑 `npm run test -- src/components/CustomWorldResultView.test.tsx`RPG 详情页删除 hook 补跑 `npm run test -- src/components/rpg-entry/useRpgEntryAgentDraftRestore.test.tsx`;角色素材工作室泥点确认补跑 `npm run test -- src/components/rpg-creation-asset-studio/RpgCreationRoleAssetStudioModal.test.tsx`;个人中心弹窗关闭按钮迁移补跑 `npm run test -- src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx -t "wallet ledger|reward code|task center|recharge|save archive|played works"`;认证入口 / 邀请码弹窗关闭按钮迁移补跑 `npm run test -- src/components/auth/AuthGate.test.tsx src/components/common/PlatformModalCloseButton.test.tsx`RPG 首页 / 公开广场 / 作品架空态迁移补跑 `npm run test -- src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx -t "mobile discover|desktop logged in home|profile played works|logged in draft bottom tab|ranking"`;历史素材选择弹窗空态迁移补跑 `npm run test -- src/components/unified-creation/shared/PuzzleHistoryAssetPickerDialog.test.tsx`;结果页普通动作和状态提示迁移补跑 `npm run test -- src/components/puzzle-result/PuzzleResultView.test.tsx``npm run test -- src/components/match3d-result/Match3DResultView.test.tsx``npm run test -- src/components/jump-hop-result/JumpHopResultView.test.tsx src/components/wooden-fish-result/WoodenFishResultView.test.tsx``npm run test -- src/components/puzzle-clear-result/PuzzleClearResultView.test.tsx src/components/edutainment-result/BabyObjectMatchResultView.test.tsx``npm run test -- src/components/square-hole-result/SquareHoleResultView.test.tsx src/components/common/PlatformModalCloseButton.test.tsx``npm run test -- src/components/visual-novel-result/VisualNovelResultView.test.tsx`;玩法创作工作台普通动作和错误提示迁移补跑 `npm run test -- src/components/puzzle-clear-creation/PuzzleClearWorkspace.test.tsx src/components/edutainment-creation/BabyObjectMatchWorkspace.test.tsx src/components/visual-novel-creation/VisualNovelAgentWorkspace.test.tsx src/components/bark-battle-creation/BarkBattleConfigEditor.test.tsx src/components/bark-battle-creation/BarkBattleResultView.test.tsx src/components/creative-agent/CreativeAgentWorkspace.test.tsx src/components/creative-agent/CreativeAgentTemplateConfirmPanel.test.tsx`creation-agent 推荐回复动作迁移补跑 `npm run test -- src/components/creation-agent/CreationAgentWorkspace.test.tsx src/components/common/PlatformActionButton.test.tsx src/components/common/platformActionButtonModel.test.ts`;创作中心重试和反馈页返回按钮迁移补跑 `npm run test -- src/components/custom-world-home/CustomWorldCreationHub.test.tsx src/components/platform-entry/PlatformFeedbackView.test.tsx src/components/common/PlatformActionButton.test.tsx`;通用生成页动作迁移补跑 `npm run test -- src/components/CustomWorldGenerationView.test.tsx src/components/common/PlatformActionButton.test.tsx`;统一创作页壳层补跑 `npm run test -- src/components/unified-creation/UnifiedCreationPage.test.tsx`;拼图创作工作台返回按钮补跑 `npm run test -- src/components/unified-creation/workspaces/PuzzleCreationWorkspace.interaction.test.tsx`;个人中心主动作按钮迁移补跑 `npm run test -- src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx -t "recharge|wallet ledger|task center|reward code|invite|community"`;复制弹窗外观迁移补跑 `npm run test -- src/components/platform-entry/PlatformErrorDialog.test.tsx src/components/common/PublishShareModal.test.tsx`;阶段完成前复扫 `rg -n "window\\.confirm|window\\.alert" src/components src/services src/hooks -g '*.tsx' -g '*.ts'`
@@ -281,6 +282,7 @@
- 2026-06-10 验证补充:角色素材工作室动作预览格收口到 `PlatformDarkOptionCard` 后,补跑 `npm run test -- src/components/rpg-creation-asset-studio/RpgCreationRoleAssetStudioModal.test.tsx src/components/common/PlatformDarkOptionCard.test.tsx`
- 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 验证补充:拼图结果页空草稿提示块收口补跑 `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

@@ -69,9 +69,11 @@
- `PlatformEmptyState` 补充:个人中心存档弹窗和玩过弹窗里的简单“暂无存档 / 暂无玩过”也使用 `surface="subpanel" size="inline"`;玩过弹窗可通过 `tone="base"` 和局部 `text-left` 保留原有白底列表语境,不在业务 JSX 重复写 `rounded-xl bg-zinc-50 px-4 py-* text-sm`
- `PlatformEmptyState` 补充:个人中心钱包账单弹窗里的“暂无账单记录”使用 `surface="subpanel" size="inline"`;业务组件只保留外边距和纵向留白,不再手写白底空态边框、字号和居中文案。
- `PlatformEmptyState` 补充:个人中心邀请弹窗里的“已填写邀请码 / 暂无成功邀请”使用 `surface="subpanel"`;业务组件保留面板分支和邀请状态机,不再为无操作提示手写白底空态。
- `PlatformEmptyState` 补充creation-agent 聊天区里的“暂无消息”使用 `surface="subpanel" size="compact"`;工作台保留消息列表滚动容器和文案,不再手写居中空态字号、颜色和高度 class。
- `PlatformTextField`:接收 `variant="input" | "textarea"``surface="platform" | "editorDark"``size="xs" | "sm" | "md" | "lg"``density="default" | "compact" | "roomy"``tone="warm" | "rose" | "emerald" | "sky"``className` 和原生 input / textarea props统一承接平台白底与 RPG 暗色弹窗里的圆角输入框、文本域、禁用态、密度、字号 / 行高和焦点色,暗色 surface 根节点固定带 `platform-text-field--editor-dark` 稳定类名。`PlatformSelectField` 复用同一套输入 chrome 承接下拉框。业务页继续持有 `value``onChange``aria-label``rows``placeholder``option` 等语义,不再重复拼 `rounded-[1rem] border border-[var(--platform-subpanel-border)] bg-white/86 px-3 py-3``rounded-[0.85rem] bg-white/90 px-3 py-2``bg-white/90 px-4 py-3`、暗色 `border-white/10 bg-black/30 px-4 py-3``focus:border-* focus:ring-*`。抓大鹅结果页作品信息、封面描述、素材名称和批量物品名称,方洞结果页主信息表单和形状 / 洞口选项字段,拼图 / 敲木鱼结果页作品信息字段,视觉小说结果页的音乐生成、作品信息、开场、运行配置、角色、场景、阶段和世界观普通文本 / 下拉字段,以及视觉小说 / 抓大鹅 / 汪汪声浪 / 宝贝识物 / 拼消消 / 跳一跳创作工作台普通输入字段已先迁移;自定义选择弹窗角色名字 / 背景补充 / 生成模式 / 世界描述和角色聊天草稿等暗色字段使用 `surface="editorDark"`。通用创作图片输入面板的提示词文本域也使用该 Module只通过局部 class 保留高度和底部浮动上传按钮避让。认证图形验证码答案、短信 / 密码登录、重置密码、绑定手机号、邀请码和账号安全表单字段,以及个人中心兑换码 / 邀请码输入使用 `surface="platform"`,业务层只保留认证 / 兑换流程、受控值、原生属性和校验提示。
- `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。
- `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不再手写同类小标题字体。
@@ -361,6 +363,7 @@
- `npm run test -- src/components/common/PlatformMediaTileGrid.test.tsx src/components/jump-hop-result/JumpHopResultView.test.tsx src/components/puzzle-clear-result/PuzzleClearResultView.test.tsx`
- `npm run test -- src/components/common/PlatformTagEditor.test.tsx src/components/puzzle-result/PuzzleResultView.test.tsx src/components/wooden-fish-result/WoodenFishResultView.test.tsx src/components/match3d-result/Match3DResultView.test.tsx`
- `npm run test -- src/components/common/PlatformTextField.test.tsx src/components/common/PlatformTagEditor.test.tsx`
- `npm run test -- src/components/creation-agent/CreationAgentWorkspace.test.tsx src/components/common/PlatformEmptyState.test.tsx src/components/common/PlatformTextField.test.tsx`
- `npm run test -- src/components/common/PlatformPillSwitch.test.tsx src/components/common/CreativeImageInputPanel.test.tsx src/components/match3d-result/Match3DResultView.test.tsx`
- `npm run test -- src/components/common/PlatformModalCloseButton.test.tsx`
- `npm run test -- src/components/common/UnifiedModal.test.tsx src/components/common/PlatformModalCloseButton.test.tsx src/components/common/UnifiedConfirmDialog.test.tsx`

View File

@@ -99,11 +99,58 @@ test('creation agent workspace keeps initial chat progress at zero percent', ()
).toContain('rounded-[1.5rem]');
expect(documentUploadButton.className).toContain('platform-icon-button');
expect(referenceUploadButton.className).toContain('platform-icon-button');
const emptyState = screen.getByText('暂无消息');
const composer = screen.getByPlaceholderText('输入消息');
expect(emptyState.className).toContain('platform-empty-state');
expect(emptyState.className).toContain('h-full');
expect(composer.className).toContain('platform-text-field');
expect(composer.className).toContain('min-h-[3rem]');
expect(composer.className).toContain('flex-1');
expect(
(progressbar.firstElementChild as HTMLElement | null)?.style.width,
).toBe('0%');
});
test('creation agent workspace keeps composer keyboard submit semantics', () => {
ensureScrollApis();
const onSubmitText = vi.fn();
render(
<CreationAgentWorkspace
session={{
sessionId: 'creation-agent-session-1',
title: null,
currentTurn: 0,
progressPercent: 0,
anchors: [],
messages: [],
}}
theme={testTheme}
loadingText="正在准备"
composerPlaceholder="输入消息"
primaryActionLabel="生成结果页"
onBack={() => {}}
onSubmitText={onSubmitText}
onPrimaryAction={() => {}}
/>,
);
const composer = screen.getByPlaceholderText('输入消息') as HTMLTextAreaElement;
fireEvent.change(composer, {
target: { value: ' 继续推进设定 ' },
});
fireEvent.keyDown(composer, { key: 'Enter', shiftKey: true });
expect(onSubmitText).not.toHaveBeenCalled();
fireEvent.keyDown(composer, { key: 'Enter' });
expect(onSubmitText).toHaveBeenCalledWith('继续推进设定');
expect(composer.value).toBe('');
});
test('creation agent workspace renders operation banner with shared status message', () => {
ensureScrollApis();

View File

@@ -9,10 +9,12 @@ import {
resolveCreationAgentProgressHint,
} from '../../services/creation-agent';
import { PlatformActionButton } from '../common/PlatformActionButton';
import { PlatformEmptyState } from '../common/PlatformEmptyState';
import { PlatformIconButton } from '../common/PlatformIconButton';
import { PlatformProgressBar } from '../common/PlatformProgressBar';
import { PlatformStatusMessage } from '../common/PlatformStatusMessage';
import { PlatformSubpanel } from '../common/PlatformSubpanel';
import { PlatformTextField } from '../common/PlatformTextField';
import { PlatformUploadPreviewCard } from '../common/PlatformUploadPreviewCard';
export type CreationAgentAnchorView = {
@@ -577,9 +579,14 @@ export function CreationAgentWorkspace({
className="min-h-0 flex-1 space-y-3 overflow-y-auto px-4 py-4"
>
{displayedMessages.length === 0 ? (
<div className="flex h-full items-center justify-center text-sm text-[var(--platform-text-soft)]">
<PlatformEmptyState
surface="subpanel"
size="compact"
tone="soft"
className="flex h-full items-center justify-center text-center"
>
</div>
</PlatformEmptyState>
) : (
displayedMessages.map((message, index) => (
<CreationAgentMessageBubble
@@ -672,12 +679,15 @@ export function CreationAgentWorkspace({
className="h-11 w-11 shrink-0"
/>
) : null}
<textarea
<PlatformTextField
variant="textarea"
value={draftText}
disabled={
isBusy || isParsingDocumentInput || isReadingReferenceImage
}
rows={2}
size="md"
density="compact"
onChange={(event) => {
setDraftText(event.target.value);
setDocumentInputError(null);
@@ -689,7 +699,7 @@ export function CreationAgentWorkspace({
}
}}
placeholder={composerPlaceholder}
className="min-h-[3rem] flex-1 resize-none bg-transparent px-2 py-2 text-sm text-[var(--platform-text-strong)] outline-none placeholder:text-[var(--platform-text-soft)]"
className="min-h-[3rem] min-w-0 flex-1 placeholder:text-[var(--platform-text-soft)]"
/>
<button
type="button"