调整桌面首页进入创作主页

桌面端打开根路径默认进入创作主页

移动端根路径继续保持推荐首页

补充首页初始路由测试与创作主页文档说明
This commit is contained in:
2026-06-21 20:37:01 +08:00
parent 7e414ec37c
commit 47023cd9be
5 changed files with 108 additions and 16 deletions
+78 -11
View File
@@ -3,9 +3,27 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { ComponentProps } from 'react';
import { describe, expect, it, vi } from 'vitest';
import { afterEach, describe, expect, it, vi } from 'vitest';
import App from './App';
import { resolveInitialSelectionStageFromPath } from './routing/appPageRoutes';
function mockMatchMedia(matches: boolean) {
Object.defineProperty(window, 'matchMedia', {
configurable: true,
writable: true,
value: vi.fn().mockImplementation((query: string) => ({
matches,
media: query,
onchange: null,
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
addListener: vi.fn(),
removeListener: vi.fn(),
dispatchEvent: vi.fn(),
})),
});
}
vi.mock('./components/platform-entry/PlatformEntryFlowShell', async () => {
const React = await import('react');
@@ -14,18 +32,30 @@ vi.mock('./components/platform-entry/PlatformEntryFlowShell', async () => {
>;
return {
PlatformEntryFlowShell: ({ setSelectionStage }: PlatformEntryFlowShellProps) =>
PlatformEntryFlowShell: ({
selectionStage,
setSelectionStage,
}: PlatformEntryFlowShellProps) =>
React.createElement(
'button',
{
type: 'button',
onClick: () => {
setSelectionStage('image-editor', {
path: '/editor/canvas?projectid=project-from-test',
});
'div',
null,
React.createElement(
'div',
{ 'data-testid': 'selection-stage' },
selectionStage,
),
React.createElement(
'button',
{
type: 'button',
onClick: () => {
setSelectionStage('image-editor', {
path: '/editor/canvas?projectid=project-from-test',
});
},
},
},
'打开最近项目',
'打开最近项目',
),
),
};
});
@@ -34,8 +64,45 @@ vi.mock('./RpgRuntimeApp', () => ({
RpgRuntimeApp: () => <div>运行态</div>,
}));
afterEach(() => {
vi.restoreAllMocks();
});
describe('resolveInitialSelectionStageFromPath', () => {
it('opens the desktop root route on the creation home stage', () => {
expect(resolveInitialSelectionStageFromPath('/', true)).toBe(
'creation-home',
);
});
it('keeps the mobile root route on the platform stage', () => {
expect(resolveInitialSelectionStageFromPath('/', false)).toBe('platform');
});
it('keeps explicit routes mapped to their own stages on desktop', () => {
expect(resolveInitialSelectionStageFromPath('/creation/puzzle', true)).toBe(
'puzzle-agent-workspace',
);
expect(resolveInitialSelectionStageFromPath('/creation', true)).toBe(
'creation-home',
);
});
});
describe('App navigation history', () => {
it('renders the desktop home URL with the creation home stage', () => {
mockMatchMedia(true);
window.history.replaceState(null, '', '/');
render(<App />);
expect(screen.getByTestId('selection-stage').textContent).toBe(
'creation-home',
);
});
it('keeps project canvas navigation as one history entry with projectid', async () => {
mockMatchMedia(true);
window.history.replaceState(null, '', '/creation');
const pushStateSpy = vi.spyOn(window.history, 'pushState');
const user = userEvent.setup();
+10 -3
View File
@@ -9,6 +9,7 @@ import {
import { useAuthUi } from './components/auth/AuthUiContext';
import { PlatformEntryFlowShell } from './components/platform-entry/PlatformEntryFlowShell';
import { getInitialPlatformDesktopLayout } from './components/platform-entry/platformEntryResponsive';
import type {
CustomWorldRuntimeLaunchOptions,
SelectionStage,
@@ -19,8 +20,8 @@ import {
normalizeAppPath,
pushAppHistoryPath,
readPublicWorkCodeFromLocationSearch,
resolveInitialSelectionStageFromPath,
resolvePathForSelectionStage,
resolveSelectionStageFromPath,
} from './routing/appPageRoutes';
import type { RpgRuntimeAppIntent } from './RpgRuntimeApp';
import type { CustomWorldProfile } from './types';
@@ -59,7 +60,10 @@ export default function App() {
isRpgRuntimeRoute(window.location.pathname),
);
const [selectionStage, setRawSelectionStage] = useState<SelectionStage>(() =>
resolveSelectionStageFromPath(window.location.pathname),
resolveInitialSelectionStageFromPath(
window.location.pathname,
getInitialPlatformDesktopLayout(),
),
);
const [runtimeReturnStage, setRuntimeReturnStage] =
useState<SelectionStage>('platform');
@@ -84,7 +88,10 @@ export default function App() {
setIsRuntimeActive(false);
setRawSelectionStage(
resolveSelectionStageFromPath(window.location.pathname),
resolveInitialSelectionStageFromPath(
window.location.pathname,
getInitialPlatformDesktopLayout(),
),
);
};
+14
View File
@@ -101,6 +101,20 @@ export function resolveSelectionStageFromPath(
return ROUTE_STAGE_BY_PATH.get(normalizeAppPath(pathname)) ?? 'platform';
}
export function resolveInitialSelectionStageFromPath(
pathname: string,
isDesktopLayout: boolean,
): SelectionStage {
const normalizedPath = normalizeAppPath(pathname);
const selectionStage = resolveSelectionStageFromPath(pathname);
if (normalizedPath === '/' && isDesktopLayout) {
return 'creation-home';
}
return selectionStage;
}
export function resolvePathForSelectionStage(stage: SelectionStage) {
return APP_STAGE_ROUTES[stage] ?? APP_STAGE_ROUTES.platform;
}