Add public work read model and smooth puzzle transitions

This commit is contained in:
kdletters
2026-05-26 16:38:27 +08:00
parent 545f315cbc
commit aeee782fe0
47 changed files with 2679 additions and 79 deletions

View File

@@ -882,6 +882,7 @@ test('运行态用 UI spritesheet 原图检测矩形裁切返回设置下一关
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('');
expect(
screen
.getByRole('button', { name: '提示' })
@@ -971,6 +972,11 @@ test('关闭通关弹窗后保留底部下一关入口', () => {
nextLevelProfileId: 'profile-1',
nextLevelId: 'puzzle-level-2',
recommendedNextWorks: [],
currentLevel: {
...clearedRun.currentLevel!,
uiSpritesheetImageSrc:
'/generated-puzzle-assets/session/ui-spritesheet/sheet.png',
},
};
renderPuzzleRuntime(
@@ -986,7 +992,9 @@ test('关闭通关弹窗后保留底部下一关入口', () => {
act(() => {
vi.advanceTimersByTime(1_400);
});
fireEvent.click(screen.getByRole('button', { name: '关闭通关弹窗' }));
act(() => {
fireEvent.click(screen.getByRole('button', { name: '关闭通关弹窗' }));
});
expect(screen.queryByRole('dialog', { name: '通关完成' })).toBeNull();
const nextButton = screen.getByRole('button', { name: //u });
@@ -1002,6 +1010,53 @@ test('关闭通关弹窗后保留底部下一关入口', () => {
vi.useRealTimers();
});
test('推荐页关闭通关弹窗后保留底部下一关入口且不叠加下一关素材图', async () => {
vi.useFakeTimers();
const runWithoutRecommendedNextProfile: PuzzleRunSnapshot = {
...clearedRun,
recommendedNextProfileId: null,
nextLevelMode: 'sameWork',
nextLevelProfileId: 'profile-1',
nextLevelId: 'puzzle-level-2',
recommendedNextWorks: [],
currentLevel: {
...clearedRun.currentLevel!,
uiSpritesheetImageSrc:
'/generated-puzzle-assets/session/ui-spritesheet/sheet.png',
},
};
renderPuzzleRuntime(
<PuzzleRuntimeShell
run={runWithoutRecommendedNextProfile}
embedded
hideBackButton
hideExitControls
onBack={vi.fn()}
onSwapPieces={vi.fn()}
onDragPiece={vi.fn()}
onAdvanceNextLevel={vi.fn()}
/>,
);
act(() => {
vi.advanceTimersByTime(1_400);
});
act(() => {
fireEvent.click(screen.getByRole('button', { name: '关闭通关弹窗' }));
});
await act(async () => {});
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.textContent?.trim()).toBe('');
vi.useRealTimers();
});
test('当前作品没有下一关时展示三个相似作品并可选择进入', () => {
vi.useFakeTimers();
const onAdvanceNextLevel = vi.fn();

View File

@@ -1933,6 +1933,7 @@ export function PuzzleRuntimeShell({
<button
type="button"
disabled={isBusy}
aria-label={hasSimilarWorkChoices ? '换个作品' : '下一关'}
onClick={() => {
if (hasSimilarWorkChoices) {
setDismissedClearKey(null);
@@ -1944,9 +1945,8 @@ export function PuzzleRuntimeShell({
levelId: run.nextLevelId ?? null,
});
}}
className="puzzle-runtime-primary-button inline-flex min-h-11 items-center gap-2 rounded-full px-5 py-2.5 text-sm font-bold transition hover:brightness-105 disabled:opacity-45"
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"
>
{hasSimilarWorkChoices ? '换个作品' : '下一关'}
<PuzzleUiSprite
src={resolvedUiSpritesheetImage}
kind="next"