This commit is contained in:
@@ -2,8 +2,12 @@ import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
APP_RUNTIME_ROUTES,
|
||||
buildPublicWorkDetailPath,
|
||||
buildPublicWorkDetailUrl,
|
||||
buildPublicWorkStagePath,
|
||||
isKnownMainAppPagePath,
|
||||
normalizeAppPath,
|
||||
readPublicWorkCodeFromLocationSearch,
|
||||
resolvePathForSelectionStage,
|
||||
resolveSelectionStageFromPath,
|
||||
} from './appPageRoutes';
|
||||
@@ -45,4 +49,22 @@ describe('appPageRoutes', () => {
|
||||
).toBe(true);
|
||||
expect(isKnownMainAppPagePath('/runtime/rpg/adventure/')).toBe(true);
|
||||
});
|
||||
|
||||
it('builds and reads public work detail query routes', () => {
|
||||
expect(buildPublicWorkDetailPath('CW-00000001')).toBe(
|
||||
'/worlds/detail?work=CW-00000001',
|
||||
);
|
||||
expect(buildPublicWorkDetailUrl('CW-00000001', 'https://example.test')).toBe(
|
||||
'https://example.test/worlds/detail?work=CW-00000001',
|
||||
);
|
||||
expect(readPublicWorkCodeFromLocationSearch('?work=CW-00000001')).toBe(
|
||||
'CW-00000001',
|
||||
);
|
||||
expect(
|
||||
buildPublicWorkStagePath('puzzle-gallery-detail', 'PZ-00000002'),
|
||||
).toBe('/gallery/puzzle/detail?work=PZ-00000002');
|
||||
expect(buildPublicWorkStagePath('big-fish-runtime', 'BF-00000003')).toBe(
|
||||
'/runtime/big-fish?work=BF-00000003',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,8 @@ import type { SelectionStage } from '../components/platform-entry';
|
||||
|
||||
export type RuntimePageRoute = 'rpg-character-select' | 'rpg-adventure';
|
||||
|
||||
export const PUBLIC_WORK_QUERY_PARAM = 'work';
|
||||
|
||||
const STAGE_ROUTE_ENTRIES = [
|
||||
['platform', '/'],
|
||||
['detail', '/worlds/detail'],
|
||||
@@ -49,6 +51,37 @@ export function resolvePathForSelectionStage(stage: SelectionStage) {
|
||||
return APP_STAGE_ROUTES[stage] ?? APP_STAGE_ROUTES.platform;
|
||||
}
|
||||
|
||||
export function readPublicWorkCodeFromLocationSearch(search: string) {
|
||||
const params = new URLSearchParams(search);
|
||||
return params.get(PUBLIC_WORK_QUERY_PARAM)?.trim() || null;
|
||||
}
|
||||
|
||||
export function buildPublicWorkDetailPath(publicWorkCode: string) {
|
||||
return buildPublicWorkStagePath('detail', publicWorkCode);
|
||||
}
|
||||
|
||||
export function buildPublicWorkStagePath(
|
||||
stage: SelectionStage,
|
||||
publicWorkCode: string,
|
||||
) {
|
||||
const code = publicWorkCode.trim();
|
||||
const stagePath = resolvePathForSelectionStage(stage);
|
||||
if (!code) {
|
||||
return stagePath;
|
||||
}
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.set(PUBLIC_WORK_QUERY_PARAM, code);
|
||||
return `${stagePath}?${params.toString()}`;
|
||||
}
|
||||
|
||||
export function buildPublicWorkDetailUrl(
|
||||
publicWorkCode: string,
|
||||
origin = window.location.origin,
|
||||
) {
|
||||
return new URL(buildPublicWorkDetailPath(publicWorkCode), origin).href;
|
||||
}
|
||||
|
||||
export function isKnownMainAppPagePath(pathname: string) {
|
||||
const normalizedPath = normalizeAppPath(pathname);
|
||||
const runtimePaths: readonly string[] = Object.values(APP_RUNTIME_ROUTES);
|
||||
@@ -59,11 +92,14 @@ export function isKnownMainAppPagePath(pathname: string) {
|
||||
}
|
||||
|
||||
export function pushAppHistoryPath(path: string) {
|
||||
const normalizedPath = normalizeAppPath(path);
|
||||
if (normalizeAppPath(window.location.pathname) === normalizedPath) {
|
||||
const nextUrl = new URL(path, window.location.origin);
|
||||
const normalizedPath = normalizeAppPath(nextUrl.pathname);
|
||||
const nextRelativeUrl = `${normalizedPath}${nextUrl.search}`;
|
||||
const currentRelativeUrl = `${normalizeAppPath(window.location.pathname)}${window.location.search}`;
|
||||
if (currentRelativeUrl === nextRelativeUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 页面阶段变化是用户可感知导航,写入 history 以支持前进后退。
|
||||
window.history.pushState(null, '', normalizedPath);
|
||||
window.history.pushState(null, '', nextRelativeUrl);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user