收口顶栏钱包快捷入口

复用 PlatformActionButton 和 PlatformIconBadge 收口创作与草稿顶栏钱包快捷入口
补强钱包快捷入口在移动端与桌面端的回归测试
更新 PlatformUiKit 收口计划和 Hermes 决策记录
This commit is contained in:
2026-06-10 16:51:40 +08:00
parent 9141540c37
commit 9a04ea55dc
4 changed files with 86 additions and 33 deletions

View File

@@ -56,6 +56,7 @@
- 2026-06-10 追加:`PlatformModalCloseButton variant="pixel"` 承接 `UnifiedModal variant="pixel"` 头部圆形关闭入口;`UnifiedModal` 只选择 `platformIcon / pixel` 变体并保留 closeDisabled、Backdrop、Escape 和 portal 语义,不再手写 X 图标、aria 和关闭按钮 class。验证命令`npm run test -- src/components/common/UnifiedModal.test.tsx src/components/common/PlatformModalCloseButton.test.tsx src/components/common/UnifiedConfirmDialog.test.tsx` - 2026-06-10 追加:`PlatformModalCloseButton variant="pixel"` 承接 `UnifiedModal variant="pixel"` 头部圆形关闭入口;`UnifiedModal` 只选择 `platformIcon / pixel` 变体并保留 closeDisabled、Backdrop、Escape 和 portal 语义,不再手写 X 图标、aria 和关闭按钮 class。验证命令`npm run test -- src/components/common/UnifiedModal.test.tsx src/components/common/PlatformModalCloseButton.test.tsx src/components/common/UnifiedConfirmDialog.test.tsx`
- 2026-06-09 追加RPG 大编辑器暗色面板内的保存和角色槽动作继续走本地 `ActionButton`,不再混用白底平台 `platform-button` class平台白底动作收口和编辑器暗色动作收口保持两套视觉边界。 - 2026-06-09 追加RPG 大编辑器暗色面板内的保存和角色槽动作继续走本地 `ActionButton`,不再混用白底平台 `platform-button` class平台白底动作收口和编辑器暗色动作收口保持两套视觉边界。
- 2026-06-10 追加:`PlatformActionButton surface="editorDark"` 承接 RPG 暗色弹窗 / 运行面板里的普通取消、确认、刷新和编组动作,支持 `size="xxs"``tone="success" | "warning"``tone="accent"` 承接暗色壳层内的琥珀实心 CTA`tone="accentSoft"` 承接依赖局部 accent 变量的柔和强调按钮。角色自定义 footer、自定义世界生成 footer、地图切换确认、营地编组普通动作和角色聊天刷新动作已迁移。暗色可选项卡仍使用 `PlatformDarkOptionCard`,像素风发送 / 强品牌动作继续保留专用布局。验证命令:`npm run test -- src/components/common/platformActionButtonModel.test.ts src/components/common/PlatformActionButton.test.tsx src/components/SelectionCustomizationModals.test.tsx src/components/CompanionCampModal.test.tsx src/components/MapModal.test.tsx src/components/CharacterChatModal.test.tsx` - 2026-06-10 追加:`PlatformActionButton surface="editorDark"` 承接 RPG 暗色弹窗 / 运行面板里的普通取消、确认、刷新和编组动作,支持 `size="xxs"``tone="success" | "warning"``tone="accent"` 承接暗色壳层内的琥珀实心 CTA`tone="accentSoft"` 承接依赖局部 accent 变量的柔和强调按钮。角色自定义 footer、自定义世界生成 footer、地图切换确认、营地编组普通动作和角色聊天刷新动作已迁移。暗色可选项卡仍使用 `PlatformDarkOptionCard`,像素风发送 / 强品牌动作继续保留专用布局。验证命令:`npm run test -- src/components/common/platformActionButtonModel.test.ts src/components/common/PlatformActionButton.test.tsx src/components/SelectionCustomizationModals.test.tsx src/components/CompanionCampModal.test.tsx src/components/MapModal.test.tsx src/components/CharacterChatModal.test.tsx`
- 2026-06-10 追加RPG 首页创作 / 草稿顶栏的钱包快捷入口通过同文件 `TopbarWalletShortcutButton` 复用 `PlatformActionButton tone="accentSoft" shape="pill" size="xs"``PlatformIconBadge`;移动端 / 桌面端继续保留 `.platform-mobile-create-wallet-chip``.platform-desktop-create-wallet-chip``.platform-desktop-search` 兼容 class承接余额截断、桌面顶栏胶囊壳和既有测试锚点点击语义仍统一走 `openRechargeOrRewardCodeModal`。验证命令:`npm run test -- src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx`
- 2026-06-10 追加RPG 大编辑器里的当前角色、可选角色、预设背景和场景连接关系等暗色信息面板通过本地 `EditorInfoPanel` 复用 `PlatformSubpanel surface="dark"`;有右侧动作的面板也只向适配器传 actions不再在业务 JSX 中重复手写暗色面板边框、底色、圆角、标题行和内容间距。验证命令:`npm run test -- src/components/CustomWorldEntityEditorModal.test.tsx -t "场景编辑器会在场景内展示槽位化多幕配置并保存"` - 2026-06-10 追加RPG 大编辑器里的当前角色、可选角色、预设背景和场景连接关系等暗色信息面板通过本地 `EditorInfoPanel` 复用 `PlatformSubpanel surface="dark"`;有右侧动作的面板也只向适配器传 actions不再在业务 JSX 中重复手写暗色面板边框、底色、圆角、标题行和内容间距。验证命令:`npm run test -- src/components/CustomWorldEntityEditorModal.test.tsx -t "场景编辑器会在场景内展示槽位化多幕配置并保存"`
- 2026-06-10 追加:作品详情底部“作品改造 / 作品编辑”和“启动”使用 `PlatformActionButton surface="platform" shape="pill" size="lg" fullWidth`;详情页保留 `platform-work-detail__remix / start` 局部 class 控制 sticky 底部栏位置、比例和品牌背景。验证命令:`npm run test -- src/components/platform-entry/PlatformWorkDetailView.test.tsx src/components/common/PlatformActionButton.test.tsx` - 2026-06-10 追加:作品详情底部“作品改造 / 作品编辑”和“启动”使用 `PlatformActionButton surface="platform" shape="pill" size="lg" fullWidth`;详情页保留 `platform-work-detail__remix / start` 局部 class 控制 sticky 底部栏位置、比例和品牌背景。验证命令:`npm run test -- src/components/platform-entry/PlatformWorkDetailView.test.tsx src/components/common/PlatformActionButton.test.tsx`
- 2026-06-10 追加:作品详情点赞按钮使用 `PlatformActionButton tone="accentSoft"`;详情页只保留纵向排布、尺寸和 `--platform-action-accent` 局部变量,不再手写点赞按钮边框、底色、文字和阴影 chrome。验证命令`npm run test -- src/components/platform-entry/PlatformWorkDetailView.test.tsx src/components/common/PlatformActionButton.test.tsx src/components/common/platformActionButtonModel.test.ts` - 2026-06-10 追加:作品详情点赞按钮使用 `PlatformActionButton tone="accentSoft"`;详情页只保留纵向排布、尺寸和 `--platform-action-accent` 局部变量,不再手写点赞按钮边框、底色、文字和阴影 chrome。验证命令`npm run test -- src/components/platform-entry/PlatformWorkDetailView.test.tsx src/components/common/PlatformActionButton.test.tsx src/components/common/platformActionButtonModel.test.ts`

View File

@@ -222,6 +222,7 @@
19.1. `CopyFeedbackButton` 支持 `actionShape`,用于在复用共享复制状态机时直接对齐 `PlatformActionButton` 的圆角外观;拼图广场详情 hero 的“分享作品”已使用 `actionSurface="editorDark" actionShape="pill"`,不再手写复制按钮 rounded / border / bg class。 19.1. `CopyFeedbackButton` 支持 `actionShape`,用于在复用共享复制状态机时直接对齐 `PlatformActionButton` 的圆角外观;拼图广场详情 hero 的“分享作品”已使用 `actionSurface="editorDark" actionShape="pill"`,不再手写复制按钮 rounded / border / bg class。
19.2. 拼图广场详情 hero 的返回、上一张 / 下一张关卡图入口迁移到 `PlatformIconButton variant="darkMini"`,修改作品和进入第 1 关迁移到 `PlatformActionButton`,分享动作继续使用 `CopyFeedbackButton` 但复用共享动作按钮 chrome详情页只保留轮播、复制和跳转语义不再手写 hero 区按钮壳。 19.2. 拼图广场详情 hero 的返回、上一张 / 下一张关卡图入口迁移到 `PlatformIconButton variant="darkMini"`,修改作品和进入第 1 关迁移到 `PlatformActionButton`,分享动作继续使用 `CopyFeedbackButton` 但复用共享动作按钮 chrome详情页只保留轮播、复制和跳转语义不再手写 hero 区按钮壳。
19.3. 个人中心充值商品卡里的“购买 / 处理中”胶囊暂保留局部 `span`,不直接套用 `PlatformActionButton`,避免在 `PlatformSubpanel as="button"` 内再嵌套交互按钮;待出现第二个同形态的非交互 action chip 后,再决定是否沉淀独立的共享展示基元。 19.3. 个人中心充值商品卡里的“购买 / 处理中”胶囊暂保留局部 `span`,不直接套用 `PlatformActionButton`,避免在 `PlatformSubpanel as="button"` 内再嵌套交互按钮;待出现第二个同形态的非交互 action chip 后,再决定是否沉淀独立的共享展示基元。
19.3.1. RPG 首页创作 / 草稿顶栏的钱包快捷入口迁移到同文件适配器 `TopbarWalletShortcutButton`,内部复用 `PlatformActionButton tone="accentSoft" shape="pill" size="xs"``PlatformIconBadge`;移动端和桌面端继续保留 `.platform-mobile-create-wallet-chip``.platform-desktop-create-wallet-chip``.platform-desktop-search` 兼容 class承接移动端余额截断、桌面顶栏胶囊底色以及既有测试锚点。入口点击仍统一走 `openRechargeOrRewardCodeModal`,不把充值 / 兑换码平台分流逻辑改散到两个顶栏分支里。
19.3. creative-agent 首页的侧边栏菜单、账号入口、开启新对话、我的创作、首页激励 CTA 和 prompt suggestion 按钮迁移到 `PlatformIconButton` / `PlatformActionButton`;首页继续保留 `creative-agent-home__*` 本地 class 承接透明顶栏、抽屉和品牌化胶囊视觉,不把视觉回收和语义收口绑成一次大改。`Beta` 徽标和历史记录纯文本行暂保留本地实现,等出现更多同构轻量列表行后再评估是否抽新的共享 row primitive。 19.3. creative-agent 首页的侧边栏菜单、账号入口、开启新对话、我的创作、首页激励 CTA 和 prompt suggestion 按钮迁移到 `PlatformIconButton` / `PlatformActionButton`;首页继续保留 `creative-agent-home__*` 本地 class 承接透明顶栏、抽屉和品牌化胶囊视觉,不把视觉回收和语义收口绑成一次大改。`Beta` 徽标和历史记录纯文本行暂保留本地实现,等出现更多同构轻量列表行后再评估是否抽新的共享 row primitive。
19.4. 大鱼吃小鱼结果页 hero 的返回入口迁移到 `PlatformIconButton variant="darkMini"`,测试 / 发布动作迁移到 `PlatformActionButton surface="editorDark"`;结果页只保留测试运行、发布提交和文案状态语义,不再手写 hero 顶栏按钮壳。 19.4. 大鱼吃小鱼结果页 hero 的返回入口迁移到 `PlatformIconButton variant="darkMini"`,测试 / 发布动作迁移到 `PlatformActionButton surface="editorDark"`;结果页只保留测试运行、发布提交和文案状态语义,不再手写 hero 顶栏按钮壳。
20. 平台方形上传入口和紧凑虚线新增入口迁移到 `PlatformUploadTile`,上传后的图片预览迁移到 `PlatformUploadPreviewCard`;反馈页上传凭证入口 / 预览、敲木鱼工作台新增功德词条入口、通用创作图片面板的提示词参考图缩略图、抓大鹅封面编辑参考图缩略图、通用输入 Composer 已选参考图条、creation-agent 已选参考图条和拼图结果页关卡引用图横条已先迁移。方形缩略图使用默认 `layout="square"`,横向“已选择参考图 / 文件名 / 素材名 / 移除”条使用 `layout="inline"`;只读引用图条不传 `onRemove`,避免公共组件额外渲染删除入口。后续继续收口结果页素材上传、工作台参考图上传、紧凑虚线新增入口等上传 / 动作块时,业务页只保留文件选择、预览数组、预览回调、删除回调、校验逻辑或新增回调,上传方块外观、主副文案、缩略图壳、预览按钮、标题行、横向已选条、移除按钮和禁用态统一由 Module 承接;工具栏中的小图标上传仍继续使用 `PlatformIconButton asChild="label"` 20. 平台方形上传入口和紧凑虚线新增入口迁移到 `PlatformUploadTile`,上传后的图片预览迁移到 `PlatformUploadPreviewCard`;反馈页上传凭证入口 / 预览、敲木鱼工作台新增功德词条入口、通用创作图片面板的提示词参考图缩略图、抓大鹅封面编辑参考图缩略图、通用输入 Composer 已选参考图条、creation-agent 已选参考图条和拼图结果页关卡引用图横条已先迁移。方形缩略图使用默认 `layout="square"`,横向“已选择参考图 / 文件名 / 素材名 / 移除”条使用 `layout="inline"`;只读引用图条不传 `onRemove`,避免公共组件额外渲染删除入口。后续继续收口结果页素材上传、工作台参考图上传、紧凑虚线新增入口等上传 / 动作块时,业务页只保留文件选择、预览数组、预览回调、删除回调、校验逻辑或新增回调,上传方块外观、主副文案、缩略图壳、预览按钮、标题行、横向已选条、移除按钮和禁用态统一由 Module 承接;工具栏中的小图标上传仍继续使用 `PlatformIconButton asChild="label"`
@@ -236,6 +237,7 @@
- `npm run test -- src/components/creative-agent/CreativeAgentHome.test.tsx src/components/auth/BindPhoneScreen.test.tsx` - `npm run test -- src/components/creative-agent/CreativeAgentHome.test.tsx src/components/auth/BindPhoneScreen.test.tsx`
- `npm run test -- src/components/creative-agent/CreativeAgentHome.test.tsx src/components/big-fish-result/BigFishResultView.test.tsx` - `npm run test -- src/components/creative-agent/CreativeAgentHome.test.tsx src/components/big-fish-result/BigFishResultView.test.tsx`
- `npm run test -- src/components/big-fish-result/BigFishResultView.test.tsx -t "renders generated formal previews with accurate status copy"` - `npm run test -- src/components/big-fish-result/BigFishResultView.test.tsx -t "renders generated formal previews with accurate status copy"`
- `npm run test -- src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx`
- `npm run test -- src/components/common/UnifiedConfirmDialog.test.tsx` - `npm run test -- src/components/common/UnifiedConfirmDialog.test.tsx`
- `npm run test -- src/components/common/useCopyFeedback.test.tsx` - `npm run test -- src/components/common/useCopyFeedback.test.tsx`
- `npm run test -- src/components/common/CopyFeedbackButton.test.tsx` - `npm run test -- src/components/common/CopyFeedbackButton.test.tsx`

View File

@@ -3535,24 +3535,37 @@ test('logged in create tab shows real wallet balance beside the brand', () => {
const topbar = container.querySelector('.platform-mobile-topbar'); const topbar = container.querySelector('.platform-mobile-topbar');
expect(topbar).toBeTruthy(); expect(topbar).toBeTruthy();
expect( expect(
topbar?.querySelector('.platform-mobile-create-wallet-chip'), within(topbar as HTMLElement).getByRole('img', {
name: / GENARRATIVE/u,
}),
).toBeTruthy(); ).toBeTruthy();
expect(topbar?.textContent).toContain('陶泥儿');
expect(topbar?.textContent).toContain('1,234泥点'); const walletButton = within(topbar as HTMLElement).getByRole('button', {
name: /^1,234$/u,
});
expect(walletButton.className).toContain('platform-mobile-create-wallet-chip');
expect(walletButton.className).toContain('platform-action-button--accent-soft');
expect(walletButton.querySelector('.platform-icon-badge')).toBeTruthy();
}); });
test('create tab wallet chip opens reward code when recharge entry is hidden', async () => { test('create tab wallet chip opens reward code when recharge entry is hidden', async () => {
const user = userEvent.setup(); const user = userEvent.setup();
mockNarrowMobileLayout(); mockNarrowMobileLayout();
render( const { container } = render(
<ProfileHomeViewHarness <ProfileHomeViewHarness
activeTab="create" activeTab="create"
profileDashboardOverrides={{ walletBalance: 70 }} profileDashboardOverrides={{ walletBalance: 70 }}
/>, />,
); );
await user.click(screen.getByRole('button', { name: /^70$/u })); const topbar = container.querySelector('.platform-mobile-topbar');
expect(topbar).toBeTruthy();
await user.click(
within(topbar as HTMLElement).getByRole('button', { name: /^70$/u }),
);
expect(await screen.findByPlaceholderText('输入兑换码')).toBeTruthy(); expect(await screen.findByPlaceholderText('输入兑换码')).toBeTruthy();
expect(mockGetRpgProfileRechargeCenter).not.toHaveBeenCalled(); expect(mockGetRpgProfileRechargeCenter).not.toHaveBeenCalled();
@@ -3562,14 +3575,25 @@ test('create tab wallet chip opens recharge when recharge entry is enabled', asy
const user = userEvent.setup(); const user = userEvent.setup();
mockWechatDesktopLayout(); mockWechatDesktopLayout();
render( const { container } = render(
<ProfileHomeViewHarness <ProfileHomeViewHarness
activeTab="create" activeTab="create"
profileDashboardOverrides={{ walletBalance: 70 }} profileDashboardOverrides={{ walletBalance: 70 }}
/>, />,
); );
await user.click(screen.getByRole('button', { name: /^70$/u })); const topbar = container.querySelector('.platform-desktop-topbar');
expect(topbar).toBeTruthy();
const walletButton = within(topbar as HTMLElement).getByRole('button', {
name: /^70$/u,
});
expect(walletButton.className).toContain('platform-desktop-create-wallet-chip');
expect(walletButton.className).toContain('platform-desktop-search');
expect(walletButton.className).toContain('platform-action-button--accent-soft');
expect(walletButton.querySelector('.platform-icon-badge')).toBeTruthy();
await user.click(walletButton);
expect(await screen.findByText('账户充值')).toBeTruthy(); expect(await screen.findByText('账户充值')).toBeTruthy();
expect(mockGetRpgProfileRechargeCenter).toHaveBeenCalledTimes(1); expect(mockGetRpgProfileRechargeCenter).toHaveBeenCalledTimes(1);

View File

@@ -1118,6 +1118,48 @@ function PublicCodeSearchBar({
); );
} }
function TopbarWalletShortcutButton({
variant,
balanceLabel,
onClick,
}: {
variant: 'mobile' | 'desktop';
balanceLabel: string;
onClick: () => void;
}) {
const isMobile = variant === 'mobile';
return (
<PlatformActionButton
tone="accentSoft"
shape="pill"
size="xs"
onClick={onClick}
aria-label={balanceLabel}
className={[
'shrink-0 [--platform-action-accent:#b65f2c]',
isMobile
? 'platform-mobile-create-wallet-chip !gap-1.5 !px-2.5 !py-1.5'
: 'platform-desktop-create-wallet-chip platform-desktop-search !px-3 !py-2.5',
]
.filter(Boolean)
.join(' ')}
>
<PlatformIconBadge
icon={<Coins className="h-3.5 w-3.5" />}
size="xs"
tone="neutral"
className={
isMobile
? '!h-6 !w-6 !bg-[#ffe0ab] !text-[#cf7b34]'
: '!bg-[#ffe0ab] !text-[#cf7b34]'
}
/>
<span>{balanceLabel}</span>
</PlatformActionButton>
);
}
function SaveArchivePreview({ function SaveArchivePreview({
entry, entry,
className, className,
@@ -7369,21 +7411,13 @@ export function RpgEntryHomeView({
</div> </div>
) : isAuthenticated && ) : isAuthenticated &&
(activeTab === 'create' || activeTab === 'saves') ? ( (activeTab === 'create' || activeTab === 'saves') ? (
<button <TopbarWalletShortcutButton
type="button" variant="mobile"
onClick={openRechargeOrRewardCodeModal} balanceLabel={
className="platform-mobile-create-wallet-chip inline-flex shrink-0 items-center gap-1.5 rounded-full border border-[#f0cfae] bg-[#fff5eb] px-2.5 py-1.5 text-xs font-black text-[#b65f2c] shadow-[0_10px_22px_rgba(174,111,73,0.12)]"
aria-label={
profileDashboardPresentation.walletBalanceWithUnitLabel profileDashboardPresentation.walletBalanceWithUnitLabel
} }
> onClick={openRechargeOrRewardCodeModal}
<span className="grid h-6 w-6 place-items-center rounded-full bg-[#ffe0ab] text-[#cf7b34]"> />
<Coins className="h-3.5 w-3.5" />
</span>
<span>
{profileDashboardPresentation.walletBalanceWithUnitLabel}
</span>
</button>
) : !isAuthenticated ? ( ) : !isAuthenticated ? (
<PlatformActionButton <PlatformActionButton
size="xs" size="xs"
@@ -7540,21 +7574,13 @@ export function RpgEntryHomeView({
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
{isAuthenticated && {isAuthenticated &&
(activeTab === 'create' || activeTab === 'saves') ? ( (activeTab === 'create' || activeTab === 'saves') ? (
<button <TopbarWalletShortcutButton
type="button" variant="desktop"
onClick={openRechargeOrRewardCodeModal} balanceLabel={
className="platform-desktop-create-wallet-chip platform-desktop-search inline-flex items-center gap-2 px-3 py-2.5 text-xs font-black text-[#b65f2c]"
aria-label={
profileDashboardPresentation.walletBalanceWithUnitLabel profileDashboardPresentation.walletBalanceWithUnitLabel
} }
> onClick={openRechargeOrRewardCodeModal}
<span className="grid h-7 w-7 place-items-center rounded-full bg-[#ffe0ab] text-[#cf7b34]"> />
<Coins className="h-3.5 w-3.5" />
</span>
<span>
{profileDashboardPresentation.walletBalanceWithUnitLabel}
</span>
</button>
) : null} ) : null}
<button <button
type="button" type="button"