This commit is contained in:
125
src/App.tsx
Normal file
125
src/App.tsx
Normal file
@@ -0,0 +1,125 @@
|
||||
import { lazy, Suspense, useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { useAuthUi } from './components/auth/AuthUiContext';
|
||||
import { PlatformEntryFlowShell } from './components/platform-entry/PlatformEntryFlowShell';
|
||||
import type { SelectionStage } from './components/platform-entry/platformEntryTypes';
|
||||
import type { HydratedSavedGameSnapshot } from './persistence/runtimeSnapshotTypes';
|
||||
import {
|
||||
APP_RUNTIME_ROUTES,
|
||||
normalizeAppPath,
|
||||
pushAppHistoryPath,
|
||||
resolvePathForSelectionStage,
|
||||
resolveSelectionStageFromPath,
|
||||
} from './routing/appPageRoutes';
|
||||
import type { RpgRuntimeAppIntent } from './RpgRuntimeApp';
|
||||
import type { CustomWorldProfile } from './types';
|
||||
|
||||
const RpgRuntimeApp = lazy(async () => {
|
||||
const module = await import('./RpgRuntimeApp');
|
||||
return {
|
||||
default: module.RpgRuntimeApp,
|
||||
};
|
||||
});
|
||||
|
||||
function isRpgRuntimeRoute(pathname: string) {
|
||||
const normalizedPath = normalizeAppPath(pathname);
|
||||
return (
|
||||
normalizedPath === APP_RUNTIME_ROUTES['rpg-character-select'] ||
|
||||
normalizedPath === APP_RUNTIME_ROUTES['rpg-adventure']
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const authUi = useAuthUi();
|
||||
const runtimeIntentTokenRef = useRef(0);
|
||||
const [runtimeIntent, setRuntimeIntent] =
|
||||
useState<RpgRuntimeAppIntent | null>(null);
|
||||
const [isRuntimeActive, setIsRuntimeActive] = useState(() =>
|
||||
isRpgRuntimeRoute(window.location.pathname),
|
||||
);
|
||||
const [selectionStage, setRawSelectionStage] = useState<SelectionStage>(() =>
|
||||
resolveSelectionStageFromPath(window.location.pathname),
|
||||
);
|
||||
|
||||
const setSelectionStage = useCallback((stage: SelectionStage) => {
|
||||
setRawSelectionStage(stage);
|
||||
pushAppHistoryPath(resolvePathForSelectionStage(stage));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const syncStageFromHistory = () => {
|
||||
if (isRpgRuntimeRoute(window.location.pathname)) {
|
||||
setIsRuntimeActive(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setIsRuntimeActive(false);
|
||||
setRawSelectionStage(
|
||||
resolveSelectionStageFromPath(window.location.pathname),
|
||||
);
|
||||
};
|
||||
|
||||
window.addEventListener('popstate', syncStageFromHistory);
|
||||
return () => window.removeEventListener('popstate', syncStageFromHistory);
|
||||
}, []);
|
||||
|
||||
const createRuntimeIntent = useCallback(
|
||||
(intent: Omit<RpgRuntimeAppIntent, 'token'>) => {
|
||||
runtimeIntentTokenRef.current += 1;
|
||||
setRuntimeIntent({
|
||||
...intent,
|
||||
token: runtimeIntentTokenRef.current,
|
||||
});
|
||||
setIsRuntimeActive(true);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const handleContinueGame = useCallback(
|
||||
(snapshot?: HydratedSavedGameSnapshot | null) => {
|
||||
createRuntimeIntent({
|
||||
kind: 'snapshot',
|
||||
snapshot: snapshot ?? null,
|
||||
});
|
||||
},
|
||||
[createRuntimeIntent],
|
||||
);
|
||||
|
||||
const handleCustomWorldSelect = useCallback(
|
||||
(customWorldProfile: CustomWorldProfile) => {
|
||||
createRuntimeIntent({
|
||||
kind: 'custom-world',
|
||||
profile: customWorldProfile,
|
||||
});
|
||||
},
|
||||
[createRuntimeIntent],
|
||||
);
|
||||
const platformThemeClass =
|
||||
authUi?.platformTheme === 'dark'
|
||||
? 'platform-theme--dark'
|
||||
: 'platform-theme--light';
|
||||
|
||||
if (isRuntimeActive) {
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<RpgRuntimeApp initialIntent={runtimeIntent} />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`platform-ui-shell platform-theme ${platformThemeClass} flex h-screen max-h-screen flex-col overflow-hidden bg-[image:var(--platform-body-fill)] p-2 font-sans text-[var(--platform-text-strong)] sm:p-4`}
|
||||
>
|
||||
<PlatformEntryFlowShell
|
||||
selectionStage={selectionStage}
|
||||
setSelectionStage={setSelectionStage}
|
||||
hasSavedGame={false}
|
||||
savedSnapshot={null}
|
||||
handleContinueGame={handleContinueGame}
|
||||
handleStartNewGame={() => {}}
|
||||
handleCustomWorldSelect={handleCustomWorldSelect}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user