fix: refine profile shortcuts and puzzle next button
This commit is contained in:
@@ -617,7 +617,11 @@ test('通关后显示结算弹窗、排行榜和下一关按钮', () => {
|
||||
expect(within(dialog).getByText('#1')).toBeTruthy();
|
||||
expect(within(dialog).getByText('测试作者')).toBeTruthy();
|
||||
|
||||
fireEvent.click(within(dialog).getByRole('button', { name: '下一关' }));
|
||||
const nextButton = within(dialog).getByRole('button', { name: '下一关' });
|
||||
expect(nextButton.textContent).toContain('下一关');
|
||||
expect(nextButton.querySelector('[data-puzzle-ui-sprite="next"]')).toBeNull();
|
||||
|
||||
fireEvent.click(nextButton);
|
||||
|
||||
expect(onAdvanceNextLevel).toHaveBeenCalledTimes(1);
|
||||
vi.useRealTimers();
|
||||
@@ -876,13 +880,16 @@ test('运行态用 UI spritesheet 原图检测矩形裁切返回设置下一关
|
||||
expect(
|
||||
screen.getByRole('button', { name: '打开拼图设置' }).className,
|
||||
).not.toContain('rounded-full');
|
||||
const nextSprite = screen
|
||||
.getByRole('button', { name: '下一关' })
|
||||
.querySelector('[data-puzzle-ui-sprite="next"]') as HTMLElement | null;
|
||||
expect(nextSprite).toBeTruthy();
|
||||
expect(nextSprite?.style.backgroundSize).toBe('320% 480%');
|
||||
expect(nextSprite?.style.backgroundPosition).toBe('50% 57.89473684210527%');
|
||||
expect(screen.getByRole('button', { name: '下一关' }).textContent).toBe('');
|
||||
const nextButton = screen.getByRole('button', { name: '下一关' });
|
||||
expect(nextButton.dataset.puzzleUiSprite).toBe('next');
|
||||
expect(nextButton.querySelector('[data-puzzle-ui-sprite="next"]')).toBeNull();
|
||||
expect(nextButton.style.backgroundSize).toBe('320% 480%');
|
||||
expect(nextButton.style.backgroundPosition).toBe('50% 57.89473684210527%');
|
||||
expect(nextButton.className).not.toContain('puzzle-runtime-primary-button');
|
||||
expect(nextButton.className).not.toContain('rounded-full');
|
||||
expect(nextButton.className).not.toContain('px-5');
|
||||
expect(nextButton.className).not.toContain('py-2.5');
|
||||
expect(nextButton.textContent).toBe('');
|
||||
expect(
|
||||
screen
|
||||
.getByRole('button', { name: '提示' })
|
||||
@@ -962,7 +969,7 @@ test('运行态在只有 UI 背景 objectKey 时仍渲染生成背景', () => {
|
||||
expect(backgroundImage).toBeTruthy();
|
||||
});
|
||||
|
||||
test('关闭通关弹窗后保留底部下一关入口', () => {
|
||||
test('关闭通关弹窗后保留底部下一关入口', async () => {
|
||||
vi.useFakeTimers();
|
||||
const onAdvanceNextLevel = vi.fn();
|
||||
const runWithoutRecommendedNextProfile: PuzzleRunSnapshot = {
|
||||
@@ -988,10 +995,31 @@ test('关闭通关弹窗后保留底部下一关入口', () => {
|
||||
onAdvanceNextLevel={onAdvanceNextLevel}
|
||||
/>,
|
||||
);
|
||||
await act(async () => {});
|
||||
|
||||
act(() => {
|
||||
vi.advanceTimersByTime(1_400);
|
||||
});
|
||||
const dialog = screen.getByRole('dialog', { name: '通关完成' });
|
||||
const dialogNextButton = within(dialog).getByRole('button', {
|
||||
name: '下一关',
|
||||
});
|
||||
expect(dialogNextButton.dataset.puzzleUiSprite).toBe('next');
|
||||
expect(
|
||||
dialogNextButton.querySelector('[data-puzzle-ui-sprite="next"]'),
|
||||
).toBeNull();
|
||||
expect(dialogNextButton.style.backgroundSize).toBe('320% 480%');
|
||||
expect(dialogNextButton.style.backgroundPosition).toBe(
|
||||
'50% 57.89473684210527%',
|
||||
);
|
||||
expect(dialogNextButton.className).not.toContain(
|
||||
'puzzle-runtime-primary-button',
|
||||
);
|
||||
expect(dialogNextButton.className).not.toContain('rounded-full');
|
||||
expect(dialogNextButton.className).not.toContain('px-5');
|
||||
expect(dialogNextButton.className).not.toContain('py-2.5');
|
||||
expect(dialogNextButton.textContent).toBe('');
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(screen.getByRole('button', { name: '关闭通关弹窗' }));
|
||||
});
|
||||
@@ -1050,9 +1078,8 @@ test('推荐页关闭通关弹窗后保留底部下一关入口且不叠加下
|
||||
expect(screen.queryByRole('dialog', { name: '通关完成' })).toBeNull();
|
||||
const nextButton = screen.getByRole('button', { name: /下一关/u });
|
||||
expect(nextButton).toBeTruthy();
|
||||
expect(
|
||||
nextButton.querySelector('[data-puzzle-ui-sprite="next"]'),
|
||||
).toBeTruthy();
|
||||
expect(nextButton.dataset.puzzleUiSprite).toBe('next');
|
||||
expect(nextButton.querySelector('[data-puzzle-ui-sprite="next"]')).toBeNull();
|
||||
expect(nextButton.textContent?.trim()).toBe('');
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
@@ -162,6 +162,15 @@ function PuzzleUiSprite({
|
||||
);
|
||||
}
|
||||
|
||||
function resolvePuzzleUiSpriteAspectRatio(
|
||||
kind: PuzzleUiSpriteKind,
|
||||
layout: PuzzleUiSpritesheetLayout | null,
|
||||
fallback: string,
|
||||
) {
|
||||
const region = layout?.regions[kind];
|
||||
return region ? `${region.width} / ${region.height}` : fallback;
|
||||
}
|
||||
|
||||
function buildMergedGroupViewModels(
|
||||
groups: PuzzleMergedGroupState[],
|
||||
pieces: PuzzleBoardPieceViewModel[],
|
||||
@@ -1221,6 +1230,22 @@ export function PuzzleRuntimeShell({
|
||||
const clearResultOverlayClassName = embedded
|
||||
? `platform-ui-shell platform-theme ${platformThemeClass} puzzle-runtime-shell puzzle-runtime-modal-overlay puzzle-runtime-modal-overlay--fixed flex items-center justify-center px-4 py-6 backdrop-blur-sm`
|
||||
: 'puzzle-runtime-modal-overlay absolute inset-0 z-40 flex items-center justify-center px-4 py-6 backdrop-blur-sm';
|
||||
const nextSpriteButtonClassName =
|
||||
'inline-flex h-12 appearance-none items-center justify-center border-0 bg-transparent p-0 leading-none shadow-none transition hover:brightness-105 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--platform-button-primary-border)] disabled:cursor-not-allowed disabled:opacity-45';
|
||||
const nextSpriteButtonStyle = hasUiSpritesheet
|
||||
? {
|
||||
...buildPuzzleUiSpriteBackgroundStyle({
|
||||
src: resolvedUiSpritesheetImage,
|
||||
kind: 'next',
|
||||
layout: uiSpritesheetLayout,
|
||||
}),
|
||||
aspectRatio: resolvePuzzleUiSpriteAspectRatio(
|
||||
'next',
|
||||
uiSpritesheetLayout,
|
||||
'2 / 1',
|
||||
),
|
||||
}
|
||||
: undefined;
|
||||
const handleBackRequest = () => {
|
||||
if (hideExitControls) {
|
||||
return;
|
||||
@@ -1457,6 +1482,8 @@ export function PuzzleRuntimeShell({
|
||||
<footer className="puzzle-runtime-dialog__line flex items-center justify-end border-t px-5 py-4">
|
||||
<button
|
||||
type="button"
|
||||
aria-label="下一关"
|
||||
data-puzzle-ui-sprite={hasUiSpritesheet ? 'next' : undefined}
|
||||
disabled={isBusy}
|
||||
onClick={() => {
|
||||
onAdvanceNextLevel({
|
||||
@@ -1464,14 +1491,23 @@ export function PuzzleRuntimeShell({
|
||||
levelId: run.nextLevelId ?? null,
|
||||
});
|
||||
}}
|
||||
className="puzzle-runtime-primary-button inline-flex items-center gap-2 rounded-full px-5 py-2.5 text-sm font-black transition hover:brightness-105 disabled:cursor-not-allowed disabled:opacity-45"
|
||||
style={nextSpriteButtonStyle}
|
||||
className={
|
||||
hasUiSpritesheet
|
||||
? nextSpriteButtonClassName
|
||||
: 'puzzle-runtime-primary-button inline-flex items-center gap-2 rounded-full px-5 py-2.5 text-sm font-black transition hover:brightness-105 disabled:cursor-not-allowed disabled:opacity-45'
|
||||
}
|
||||
>
|
||||
{isBusy ? (
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<ArrowRight className="h-4 w-4" />
|
||||
{hasUiSpritesheet ? null : (
|
||||
<>
|
||||
{isBusy ? (
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<ArrowRight className="h-4 w-4" />
|
||||
)}
|
||||
下一关
|
||||
</>
|
||||
)}
|
||||
下一关
|
||||
</button>
|
||||
</footer>
|
||||
) : null}
|
||||
@@ -1933,6 +1969,7 @@ export function PuzzleRuntimeShell({
|
||||
<button
|
||||
type="button"
|
||||
disabled={isBusy}
|
||||
data-puzzle-ui-sprite={hasUiSpritesheet ? 'next' : undefined}
|
||||
aria-label={hasSimilarWorkChoices ? '换个作品' : '下一关'}
|
||||
onClick={() => {
|
||||
if (hasSimilarWorkChoices) {
|
||||
@@ -1945,16 +1982,18 @@ export function PuzzleRuntimeShell({
|
||||
levelId: run.nextLevelId ?? null,
|
||||
});
|
||||
}}
|
||||
className="puzzle-runtime-primary-button inline-flex min-h-11 items-center justify-center rounded-full px-5 py-2.5 text-sm font-bold transition hover:brightness-105 disabled:opacity-45"
|
||||
style={nextSpriteButtonStyle}
|
||||
className={
|
||||
hasUiSpritesheet
|
||||
? nextSpriteButtonClassName
|
||||
: 'puzzle-runtime-primary-button inline-flex min-h-11 items-center justify-center rounded-full px-5 py-2.5 text-sm font-bold transition hover:brightness-105 disabled:opacity-45'
|
||||
}
|
||||
>
|
||||
<PuzzleUiSprite
|
||||
src={resolvedUiSpritesheetImage}
|
||||
kind="next"
|
||||
layout={uiSpritesheetLayout}
|
||||
className="h-8 w-12 rounded-full"
|
||||
/>
|
||||
{resolvedUiSpritesheetImage ? null : (
|
||||
<ArrowRight className="h-4 w-4" />
|
||||
{hasUiSpritesheet ? null : (
|
||||
<>
|
||||
<ArrowRight className="h-4 w-4" />
|
||||
{hasSimilarWorkChoices ? '换个作品' : '下一关'}
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
) : null}
|
||||
|
||||
@@ -2412,6 +2412,21 @@ test('mobile profile page matches the reference layout sections', async () => {
|
||||
.querySelector('.platform-profile-shortcut-grid')
|
||||
?.classList.contains('platform-profile-shortcut-grid'),
|
||||
).toBe(true);
|
||||
expect(
|
||||
shortcutRegion
|
||||
.querySelector('.platform-profile-shortcut-grid')
|
||||
?.className,
|
||||
).toContain('!grid-cols-4');
|
||||
expect(
|
||||
shortcutRegion
|
||||
.querySelector('.platform-profile-shortcut-grid')
|
||||
?.className,
|
||||
).toContain('w-full');
|
||||
for (const shortcutButton of shortcutRegion.querySelectorAll(
|
||||
'.platform-profile-shortcut-button',
|
||||
)) {
|
||||
expect(shortcutButton.className).toContain('w-full');
|
||||
}
|
||||
for (const label of [
|
||||
'泥点充值',
|
||||
'兑换码',
|
||||
|
||||
@@ -2434,7 +2434,7 @@ function ProfileShortcutButton({
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClick ?? undefined}
|
||||
className="platform-profile-shortcut-button flex min-h-[5.25rem] flex-col items-center justify-center gap-2 px-2.5 py-3 text-center transition"
|
||||
className="platform-profile-shortcut-button flex min-h-[5.25rem] w-full flex-col items-center justify-center gap-2 px-2.5 py-3 text-center transition"
|
||||
>
|
||||
<div className="platform-profile-shortcut-button__icon">
|
||||
{imageSrc ? (
|
||||
@@ -6368,7 +6368,7 @@ export function RpgEntryHomeView({
|
||||
className="platform-profile-shortcut-panel"
|
||||
aria-label="常用功能"
|
||||
>
|
||||
<div className="platform-profile-shortcut-grid">
|
||||
<div className="platform-profile-shortcut-grid grid w-full !grid-cols-4">
|
||||
<ProfileShortcutButton
|
||||
label="泥点充值"
|
||||
subLabel="充值泥点"
|
||||
|
||||
Reference in New Issue
Block a user