154 lines
3.5 KiB
TypeScript
154 lines
3.5 KiB
TypeScript
/* eslint-disable react-refresh/only-export-components */
|
|
|
|
import { type ComponentType, lazy, type LazyExoticComponent } from 'react';
|
|
|
|
import type { PresetEditorTab } from '../components/PresetEditor';
|
|
|
|
type AppRouteComponent = LazyExoticComponent<
|
|
ComponentType<Record<string, unknown>>
|
|
>;
|
|
|
|
export type AppRouteMatch =
|
|
| {
|
|
kind: 'game';
|
|
}
|
|
| {
|
|
kind: 'preset-editor';
|
|
initialTab: PresetEditorTab;
|
|
}
|
|
| {
|
|
kind: 'qwen-sprite-tool';
|
|
};
|
|
|
|
export type ResolvedAppRoute = {
|
|
kind: AppRouteMatch['kind'];
|
|
loadingEyebrow: string;
|
|
loadingText: string;
|
|
Component: AppRouteComponent;
|
|
componentProps?: Record<string, unknown>;
|
|
};
|
|
|
|
const GameApp = lazy(() => import('../App')) as AppRouteComponent;
|
|
const PresetEditorApp = lazy(async () => {
|
|
const module = await import('../components/PresetEditor');
|
|
|
|
return {
|
|
default: module.PresetEditor,
|
|
};
|
|
}) as AppRouteComponent;
|
|
const QwenSpriteToolApp = lazy(
|
|
() => import('../tools/QwenSpriteSheetTool'),
|
|
) as AppRouteComponent;
|
|
|
|
const PRESET_EDITOR_ROUTES: Array<{
|
|
prefixes: string[];
|
|
initialTab: PresetEditorTab;
|
|
}> = [
|
|
{
|
|
prefixes: ['/character-asset-studio', '/asset-studio'],
|
|
initialTab: 'assets',
|
|
},
|
|
{
|
|
prefixes: ['/function-editor', '/behavior-editor'],
|
|
initialTab: 'functions',
|
|
},
|
|
{
|
|
prefixes: ['/item-editor'],
|
|
initialTab: 'items',
|
|
},
|
|
{
|
|
prefixes: ['/npc-editor'],
|
|
initialTab: 'npcs',
|
|
},
|
|
{
|
|
prefixes: ['/preset-editor'],
|
|
initialTab: 'characters',
|
|
},
|
|
];
|
|
|
|
const QWEN_SPRITE_TOOL_PREFIXES = [
|
|
'/qwen-sprite-tool',
|
|
'/sprite-tool',
|
|
'/pixelmotion-qwen',
|
|
];
|
|
|
|
function normalizeRoutePath(pathname: string) {
|
|
const trimmedPathname = pathname.trim().toLowerCase();
|
|
|
|
if (!trimmedPathname || trimmedPathname === '/') {
|
|
return '/';
|
|
}
|
|
|
|
return trimmedPathname.replace(/\/+$/u, '');
|
|
}
|
|
|
|
function matchesRoutePrefix(pathname: string, prefix: string) {
|
|
const normalizedPrefix = normalizeRoutePath(prefix);
|
|
|
|
return (
|
|
pathname === normalizedPrefix || pathname.startsWith(`${normalizedPrefix}/`)
|
|
);
|
|
}
|
|
|
|
export function matchAppRoute(pathname: string): AppRouteMatch {
|
|
const normalizedPathname = normalizeRoutePath(pathname);
|
|
const isQwenSpriteToolRoute = QWEN_SPRITE_TOOL_PREFIXES.some((prefix) =>
|
|
matchesRoutePrefix(normalizedPathname, prefix),
|
|
);
|
|
|
|
if (isQwenSpriteToolRoute) {
|
|
return {
|
|
kind: 'qwen-sprite-tool',
|
|
};
|
|
}
|
|
|
|
const presetRoute = PRESET_EDITOR_ROUTES.find((route) =>
|
|
route.prefixes.some((prefix) =>
|
|
matchesRoutePrefix(normalizedPathname, prefix),
|
|
),
|
|
);
|
|
|
|
if (presetRoute) {
|
|
return {
|
|
kind: 'preset-editor',
|
|
initialTab: presetRoute.initialTab,
|
|
};
|
|
}
|
|
|
|
return {
|
|
kind: 'game',
|
|
};
|
|
}
|
|
|
|
export function resolveAppRoute(pathname: string): ResolvedAppRoute {
|
|
const matchedRoute = matchAppRoute(pathname);
|
|
|
|
if (matchedRoute.kind === 'qwen-sprite-tool') {
|
|
return {
|
|
kind: matchedRoute.kind,
|
|
loadingEyebrow: '正在载入精灵表工坊',
|
|
loadingText: '正在载入 Qwen 精灵表工具...',
|
|
Component: QwenSpriteToolApp,
|
|
};
|
|
}
|
|
|
|
if (matchedRoute.kind === 'preset-editor') {
|
|
return {
|
|
kind: matchedRoute.kind,
|
|
loadingEyebrow: '正在载入编辑器',
|
|
loadingText: '正在载入编辑器...',
|
|
Component: PresetEditorApp,
|
|
componentProps: {
|
|
initialTab: matchedRoute.initialTab,
|
|
},
|
|
};
|
|
}
|
|
|
|
return {
|
|
kind: 'game',
|
|
loadingEyebrow: '正在载入游戏',
|
|
loadingText: '正在载入冒险...',
|
|
Component: GameApp,
|
|
};
|
|
}
|