继续收口运行态浮层暗色动作与行卡

统一运行态浮层里的标准暗色动作按钮到共享 PlatformActionButton
统一设置面板里的运行统计入口到共享 PlatformSubpanel 按钮壳
补充 PlatformUiKit 收口计划、共享决策记录与 quest offer 组件测试护栏
This commit is contained in:
2026-06-11 02:33:31 +08:00
parent 60ef4ead71
commit ab5a0efe50
4 changed files with 49 additions and 37 deletions

View File

@@ -2080,6 +2080,7 @@
- 决策:白底 / 暗色面板里的轻量空态和普通 CTA 继续向共享组件收口。`PuzzleResultView.tsx` 的缺草稿提示、`RpgCreationAssetDebugPanel.tsx` 的空诊断提示、`VisualNovelEntityGrid` 的空实体列表、`AccountModal.tsx` 里账号安全分区的“无安全限制 / 无登录设备 / 无操作记录”以及 `LoginScreen.tsx` 的“当前登录入口暂不可用”都改为 `PlatformEmptyState``Match3DResultView.tsx` 的引用素材列表直接复用 `PlatformAssetPickerGrid` 自己的空态;`AdventureEntityModal.tsx` 的私聊按钮、`InventoryPanel.tsx` 的锻造 / 合成按钮、`RpgCreationRoleAssetStudioModalImpl.tsx``RpgCreationEntityEditorShared.tsx` 里的局部 `ActionButton` 包装层,以及 `RpgAdventurePanel.tsx` / `RpgAdventurePanelOverlays.tsx` 里标准 runtime CTA 都改为委托 `PlatformActionButton surface="editorDark"`。后续白底子面板里的只读空态优先使用 `PlatformEmptyState surface="subpanel"`;暗色编辑 / 运行面板里的普通动作优先使用 `PlatformActionButton surface="editorDark"`,若业务仍需 `stopPropagation`、tone 映射、运行态 icon 排版或局部字号,可保留薄包装层,但不要再直接写原生 `<button>` 基础 chrome。
- 决策:`CustomWorldNpcVisualEditor.tsx` 的本地 `ActionButton``SkillEffectPreview.tsx` 的“重新预览”按钮也继续并入这条暗色按钮收口线,统一委托 `PlatformActionButton surface="editorDark"`;局部包装层只保留 `stopPropagation`、图标排布、`tone` 映射和极少量视觉微调。后续暗色编辑器里的局部动作按钮若只是普通 CTA不再新增原生 `<button>` 实现,优先沿用“薄包装 + 共享按钮本体”模式。
- 决策RPG 创作侧标准 dark header / footer 动作也继续纳入同一条按钮收口线。`RpgCreationRoleAssetStudioModalImpl.tsx` 的 header“关闭”、`RpgCreationEntityEditorShared.tsx` 的 footer“取消”以及 `RpgCreationRoleAssetStudioFooter.tsx` 的“保存到当前角色”都改为委托 `PlatformActionButton surface="editorDark"`;局部壳层只保留布局、宽度/字号贴合和少量 tone 语义,不再为标准 dark close / cancel / save CTA 单独维护原生 `<button>` 基础 chrome。
- 决策RPG runtime overlay 里的标准 dark CTA 和可点击 dark row 也继续纳入这条收口线。`RpgAdventurePanelOverlays.tsx` 的 goal panel“知道了”、任务详情里的“领取任务 / 返回交付”、任务完成提示里的“打开任务日志”都改为委托 `PlatformActionButton surface="editorDark"`;设置面板里的“运行统计”入口改为 `PlatformSubpanel as="button" surface="dark"`。像素风 choice button、HUD launcher、奖励物品格和输入 composer 保持 runtime 专属语义,不继续硬并到普通平台按钮。
- 验证方式:`npm run test -- src/components/common/PlatformAsyncStatePanel.test.tsx src/components/platform-entry/PlatformProfileReferralModal.test.tsx src/components/platform-entry/PlatformProfileWalletLedgerModal.test.tsx src/components/platform-entry/PlatformProfilePlayedWorksModal.test.tsx src/components/platform-entry/PlatformProfileTaskCenterModal.test.tsx src/components/platform-entry/PlatformProfileRechargeModal.test.tsx src/components/common/PlatformSegmentedTabs.test.tsx src/components/custom-world-home/CustomWorldCreationHub.test.tsx src/components/custom-world-home/CustomWorldCreationHub.interaction.test.tsx``npm run test -- src/components/common/PlatformModalCloseButton.test.tsx src/components/PixelCloseButton.test.tsx src/components/CharacterChatModal.test.tsx src/components/MapModal.test.tsx``npm run test -- src/components/common/useMudPointConfirmController.test.tsx src/components/match3d-result/Match3DResultView.test.tsx src/components/unified-creation/workspaces/PuzzleCreationWorkspace.interaction.test.tsx src/components/unified-creation/workspaces/Match3DCreationWorkspace.interaction.test.tsx src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx src/components/platform-entry/PlatformProfileRechargeModal.test.tsx src/components/CustomWorldEntityEditorModal.test.tsx src/components/rpg-creation-result/RpgCreationResultActionBar.test.tsx src/components/unified-creation/shared/PuzzleHistoryAssetPickerDialog.test.tsx src/components/puzzle-result/PuzzleResultView.test.tsx``npm run test -- src/components/common/CopyFeedbackButton.test.tsx src/components/common/PlatformActionButton.test.tsx src/components/AdventureEntityModal.test.tsx src/components/InventoryPanel.test.tsx src/components/rpg-creation-result/RpgCreationAssetDebugPanel.test.tsx src/components/visual-novel-result/VisualNovelResultView.test.tsx src/components/common/PlatformEmptyState.test.tsx src/components/rpg-creation-asset-studio/RpgCreationRoleAssetStudioModal.test.tsx src/components/auth/AccountModal.test.tsx src/components/rpg-runtime-panels/RpgAdventurePanel.test.tsx src/components/rpg-runtime-panels/RpgAdventurePanel.npcChat.test.tsx src/components/rpg-runtime-panels/RpgAdventurePanel.questOffer.test.tsx``npm run typecheck``npm run check:encoding``git diff --check`
## 2026-05-26 敲木鱼发布后作品架与推荐流刷新口径

View File

@@ -266,6 +266,7 @@
21. 图片编辑面板中的白底胶囊开关迁移到 `PlatformPillSwitch`;通用创作图片面板和抓大鹅封面编辑的 `AI重绘` 已先迁移。后续同类开关只保留受控布尔值和状态变更回调switch 输入语义、轨道、圆点、白底浮层和禁用态统一由 Module 承接。
22. 设置面板、结果页运行配置和工作台白底配置项中的整行开关迁移到 `PlatformToggleRow`视觉小说结果页、runtime 设置面板和拼消消创作工作台 AI 生成底图开关已先迁移。后续整行配置项只保留字段写回和可选点击动作,不再重复开关行 chrome、checkbox class 或状态 pill。
22.1. RPG 创作侧标准 dark header / footer 动作继续向共享按钮收口:`RpgCreationRoleAssetStudioModalImpl.tsx` 的 header“关闭”、`RpgCreationEntityEditorShared.tsx` 的 footer“取消”、`RpgCreationRoleAssetStudioFooter.tsx` 的“保存到当前角色”都改为委托 `PlatformActionButton surface="editorDark"`。局部壳层只继续保留 `stopPropagation`、tone 映射、布局和极少量字号/宽度贴合;标准暗色编辑器里的 close / cancel / save CTA 不再各自手写原生 `<button>` 基础 chrome。
22.2. RPG runtime overlay 里的标准 dark CTA 和可点击 dark row 继续向共享原子收口:`RpgAdventurePanelOverlays.tsx` 的 goal panel“知道了”、任务详情里的“领取任务 / 返回交付”、任务完成提示里的“打开任务日志”都改为委托 `PlatformActionButton surface="editorDark"`;设置面板里的“运行统计”入口改为 `PlatformSubpanel as="button" surface="dark"`。像素风 choice button、HUD launcher、奖励物品格和输入 composer 这类 runtime 专属控件继续保留独立语义,不并回普通平台按钮。
## 验证

View File

@@ -351,7 +351,11 @@ test('quest offer accept button reuses the shared accepted-quest follow-up chain
expect(affinityRewardClassName).toContain('border-rose-300/18');
expect(currencyRewardClassName).toContain('border-amber-300/18');
expect(experienceRewardClassName).toContain('border-sky-400/18');
await user.click(await screen.findByRole('button', { name: '领取任务' }));
const acceptButton = await screen.findByRole('button', { name: '领取任务' });
expect(acceptButton.className).toContain(
'platform-action-button--editor-dark',
);
await user.click(acceptButton);
expect((await screen.findAllByText('任务进度0/1')).length).toBeGreaterThan(
0,
@@ -452,7 +456,12 @@ test('adventure statistics panel reuses dark PlatformSubpanel chrome', async ()
render(<QuestOfferHarness />);
await user.click(screen.getByRole('button', { name: '打开设置' }));
await user.click(await screen.findByRole('button', { name: //u }));
const statsEntryButton = await screen.findByRole('button', {
name: //u,
});
expect(statsEntryButton.className).toContain('bg-black/25');
expect(statsEntryButton.className).toContain('border-white/10');
await user.click(statsEntryButton);
const statsTitle = await screen.findByText('冒险统计');
const statsDialog = statsTitle.closest('.pixel-modal-shell');
@@ -496,9 +505,13 @@ test('quest completion notice reuses dark PlatformSubpanel chrome', async () =>
const noticeText = await screen.findByText('可前往任务日志领取奖励。');
const noticeClassName = findNearestClassName(noticeText, 'bg-black/25');
const openQuestLogButton = screen.getByRole('button', { name: '打开任务日志' });
expect(screen.getByText('奖励已准备')).toBeTruthy();
expect(noticeClassName).toContain('border-emerald-400/15');
expect(openQuestLogButton.className).toContain(
'platform-action-button--editor-dark',
);
});
test('battle reward modal reuses dark PlatformSubpanel chrome', async () => {

View File

@@ -1042,17 +1042,16 @@ export function RpgAdventurePanelOverlays({
</PlatformActionButton>
) : null}
<button
type="button"
<PlatformActionButton
surface="editorDark"
tone="primary"
size="xxs"
shape="pill"
onClick={closeGoalPanel}
className="pixel-nine-slice pixel-pressable px-4 py-2 text-xs text-white"
style={getNineSliceStyle(UI_CHROME.choiceButton, {
paddingX: 14,
paddingY: 8,
})}
className="px-4 py-2 text-xs"
>
</button>
</PlatformActionButton>
</div>
</motion.div>
</motion.div>
@@ -1126,10 +1125,14 @@ export function RpgAdventurePanelOverlays({
</div>
</div>
<button
<PlatformSubpanel
as="button"
type="button"
onClick={() => setIsStatsPanelOpen(true)}
className="w-full rounded-2xl border border-white/10 bg-black/25 px-4 py-3 text-left transition hover:border-white/20"
surface="dark"
radius="sm"
padding="sm"
className="w-full text-left transition hover:border-white/20"
>
<div className="flex items-center justify-between gap-3">
<div>
@@ -1142,7 +1145,7 @@ export function RpgAdventurePanelOverlays({
</div>
<BarChart3 className="h-4 w-4 text-amber-200/75" />
</div>
</button>
</PlatformSubpanel>
<PlatformActionButton
surface="editorDark"
@@ -1463,8 +1466,11 @@ export function RpgAdventurePanelOverlays({
{isPendingSelectedQuest && (
<div className="flex justify-end">
<button
type="button"
<PlatformActionButton
surface="editorDark"
tone="primary"
size="xs"
shape="pill"
onClick={() => {
const acceptedQuestId = onAcceptPendingNpcQuestOffer();
if (!acceptedQuestId) return;
@@ -1472,31 +1478,24 @@ export function RpgAdventurePanelOverlays({
setSelectedRewardItemId(null);
setSelectedBattleRewardItemId(null);
}}
className="pixel-nine-slice pixel-pressable px-4 py-2 text-xs text-white"
style={getNineSliceStyle(UI_CHROME.choiceButton, {
paddingX: 14,
paddingY: 8,
})}
>
</button>
</PlatformActionButton>
</div>
)}
{isQuestReadyToClaim(selectedQuest) &&
!isPendingSelectedQuest && (
<div className="flex justify-end">
<button
type="button"
<PlatformActionButton
surface="editorDark"
tone="ghost"
size="xs"
shape="pill"
onClick={() => setSelectedQuestId(null)}
className="pixel-nine-slice pixel-pressable px-4 py-2 text-xs text-white"
style={getNineSliceStyle(UI_CHROME.choiceButton, {
paddingX: 14,
paddingY: 8,
})}
>
</button>
</PlatformActionButton>
</div>
)}
</div>
@@ -1548,8 +1547,11 @@ export function RpgAdventurePanelOverlays({
: '可前往任务日志领取奖励。'}
</PlatformSubpanel>
<div className="flex justify-center">
<button
type="button"
<PlatformActionButton
surface="editorDark"
tone="primary"
size="xs"
shape="pill"
onClick={() => {
questUi.acknowledgeQuestCompletion(
completionNoticeQuest.id,
@@ -1557,14 +1559,9 @@ export function RpgAdventurePanelOverlays({
setCompletionNoticeQuestId(null);
setIsQuestPanelOpen(true);
}}
className="pixel-nine-slice pixel-pressable px-4 py-2 text-xs text-white"
style={getNineSliceStyle(UI_CHROME.choiceButton, {
paddingX: 14,
paddingY: 8,
})}
>
</button>
</PlatformActionButton>
</div>
</div>
</motion.div>