继续收口编辑器空态与暗色动作按钮

视觉小说实体列表空态复用 PlatformEmptyState
角色素材工作室局部按钮改为委托 PlatformActionButton
RPG大编辑器局部按钮改为委托 PlatformActionButton
更新 PlatformUiKit 收口文档与团队决策记录
This commit is contained in:
2026-06-11 01:52:47 +08:00
parent 06bf03a28c
commit 402b847c7f
7 changed files with 59 additions and 23 deletions

View File

@@ -1055,7 +1055,11 @@ test('基本设定面板只编辑六个角色维度名称', async () => {
expect(screen.queryByLabelText('正向信号')).toBeNull();
expect(screen.queryByLabelText('战斗体现')).toBeNull();
await user.click(screen.getByRole('button', { name: //u }));
const saveButton = screen.getByRole('button', { name: //u });
expect(saveButton.className).toContain('platform-action-button--editor-dark');
expect(saveButton.className).toContain('rounded-full');
await user.click(saveButton);
expect(savedProfileRef.current?.attributeSchema.slots[0]?.name).toBe('潮骨');
});

View File

@@ -23,6 +23,7 @@ import {
import { buildProjectPixelStyleReferenceBoard } from '../asset-studio/projectPixelStyleReference';
import { useAuthUi } from '../auth/AuthUiContext';
import { CharacterAnimator } from '../CharacterAnimator';
import { PlatformActionButton } from '../common/PlatformActionButton';
import { PlatformMudPointConfirmDialog } from '../common/PlatformMudPointConfirmDialog';
import {
CORE_ACTIONS,
@@ -206,16 +207,21 @@ function ActionButton({
disabled?: boolean;
tone?: 'default' | 'sky' | 'green';
}) {
const resolvedTone =
tone === 'green' ? 'success' : tone === 'sky' ? 'primary' : 'ghost';
const toneClassName =
tone === 'green'
? 'border-emerald-400/30 bg-emerald-500/10 text-emerald-100 hover:bg-emerald-500/20'
? 'border-emerald-400/30 bg-emerald-500/10 text-emerald-100 hover:border-emerald-300/40 hover:bg-emerald-500/20 hover:text-white'
: tone === 'sky'
? 'border-sky-300/22 bg-sky-500/12 text-sky-50 hover:border-sky-200/40 hover:text-white'
: 'border-white/12 bg-black/20 text-zinc-200 hover:border-white/22 hover:text-white';
? 'border-sky-300/22 bg-sky-500/12 text-sky-50 hover:border-sky-200/40 hover:bg-sky-500/15 hover:text-white'
: 'border-white/12 bg-black/20 text-zinc-200 hover:border-white/22 hover:bg-black/20 hover:text-white';
return (
<button
type="button"
<PlatformActionButton
surface="editorDark"
tone={resolvedTone}
shape="pill"
align="start"
onPointerDown={(event) => {
event.stopPropagation();
}}
@@ -227,7 +233,12 @@ function ActionButton({
onClick();
}}
disabled={disabled}
className={`inline-flex items-center gap-2 rounded-full border px-4 py-2 text-sm font-semibold transition-colors ${toneClassName} ${disabled ? 'cursor-not-allowed opacity-45' : ''}`}
className={[
'py-2 font-semibold leading-tight disabled:opacity-45',
toneClassName,
]
.filter(Boolean)
.join(' ')}
>
{icon ?? null}
<span className="flex flex-col items-start leading-tight">
@@ -236,7 +247,7 @@ function ActionButton({
<span className="text-[11px] font-medium opacity-70">{subLabel}</span>
) : null}
</span>
</button>
</PlatformActionButton>
);
}

View File

@@ -95,6 +95,7 @@ import {
import { useAuthUi } from '../auth/AuthUiContext';
import { CharacterAnimator } from '../CharacterAnimator';
import { PlatformAcknowledgeStatusDialog } from '../common/PlatformAcknowledgeStatusDialog';
import { PlatformActionButton } from '../common/PlatformActionButton';
import { PlatformAssetPickerGrid } from '../common/PlatformAssetPickerCard';
import { PlatformEmptyState } from '../common/PlatformEmptyState';
import { PlatformIconButton } from '../common/PlatformIconButton';
@@ -1665,16 +1666,22 @@ function ActionButton({
disabled?: boolean;
className?: string;
}) {
const buttonTone =
tone === 'sky' ? 'primary' : tone === 'rose' ? 'danger' : 'ghost';
const toneClassName =
tone === 'sky'
? 'border-sky-300/22 bg-sky-500/12 text-sky-50 hover:border-sky-200/40 hover:text-white'
? 'border-sky-300/22 bg-sky-500/12 text-sky-50 hover:border-sky-200/40 hover:bg-sky-500/18 hover:text-white'
: tone === 'rose'
? 'border-rose-300/22 bg-rose-500/12 text-rose-50 hover:border-rose-200/40 hover:text-white'
? 'border-rose-300/22 bg-rose-500/12 text-rose-50 hover:border-rose-200/40 hover:bg-rose-500/16 hover:text-white'
: 'border-white/12 bg-black/20 text-zinc-200 hover:border-white/22 hover:text-white';
return (
<button
<PlatformActionButton
type="button"
surface="editorDark"
tone={buttonTone}
size="sm"
shape="pill"
onPointerDown={(event) => {
event.stopPropagation();
}}
@@ -1686,10 +1693,16 @@ function ActionButton({
onClick();
}}
disabled={disabled}
className={`rounded-full border px-4 py-2 text-sm font-semibold transition-colors ${toneClassName} ${disabled ? 'cursor-not-allowed opacity-45' : ''} ${className}`}
className={[
'py-2 font-semibold disabled:opacity-45',
toneClassName,
className,
]
.filter(Boolean)
.join(' ')}
>
{label}
</button>
</PlatformActionButton>
);
}

View File

@@ -113,7 +113,7 @@ test('visual novel entity list items use interactive PlatformSubpanel shells', a
expect(characterCard.className).toContain('rounded-[1.25rem]');
});
test('visual novel empty entity list uses PlatformSubpanel shell', async () => {
test('visual novel empty entity list uses PlatformEmptyState shell', async () => {
const user = userEvent.setup();
const emptyCharacterDraft = {
...mockVisualNovelDraft,
@@ -126,11 +126,17 @@ test('visual novel empty entity list uses PlatformSubpanel shell', async () => {
await user.click(screen.getByRole('button', { name: '角色' }));
const emptyPanel = screen.getByText('暂无角色').closest('.platform-subpanel');
const emptyPanel = screen
.getByText('暂无角色')
.closest('.platform-empty-state');
expect(emptyPanel?.className).toContain('platform-subpanel');
expect(emptyPanel?.className).toContain('platform-empty-state');
expect(emptyPanel?.className).toContain('bg-white/74');
expect(emptyPanel?.className).toContain('rounded-[1.25rem]');
expect(emptyPanel?.className).toContain('min-h-32');
expect(emptyPanel?.className).toContain(
'text-[var(--platform-text-soft)]',
);
});
test('visual novel result opens complex editors as a dialog', async () => {

View File

@@ -1848,12 +1848,13 @@ function VisualNovelEntityGrid({
</PlatformSubpanel>
))}
{items.length <= 0 ? (
<PlatformSubpanel
as="div"
className="flex min-h-32 items-center justify-center rounded-[1.25rem] px-4 text-sm text-[var(--platform-text-soft)]"
<PlatformEmptyState
surface="subpanel"
size="inline"
className="flex min-h-32 items-center justify-center rounded-[1.25rem] p-4 font-normal"
>
{emptyText}
</PlatformSubpanel>
</PlatformEmptyState>
) : null}
</div>
</div>