feat(ui): screen-level history for the app-shell (Back → lobby)
Mirror the screen into browser history via SvelteKit shallow routing (pushState/replaceState with page.state) so Back/Forward move between screens while the URL stays at /game/. Overlays (game, lobby-create) push; lobby/login replace. A popstate→page.state effect syncs the store back without re-pushing (no loop); the boot stamp puts a restored overlay above the load entry so Back falls through to lobby. In-game view switches never touch history. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,8 @@
|
||||
// in the shell via SvelteKit shallow routing; this module is the source of
|
||||
// truth, history only mirrors it.
|
||||
|
||||
import { pushState, replaceState } from "$app/navigation";
|
||||
|
||||
export type AppScreen = "login" | "lobby" | "lobby-create" | "game";
|
||||
|
||||
export type GameView =
|
||||
@@ -158,6 +160,34 @@ class AppScreenStore {
|
||||
this.#gameId = null;
|
||||
}
|
||||
persist();
|
||||
this.#syncHistory();
|
||||
}
|
||||
|
||||
/**
|
||||
* syncFromHistory applies a screen restored from browser history (a
|
||||
* Back/Forward popstate) WITHOUT pushing a new entry. An absent/unknown
|
||||
* screen (the load entry beneath an overlay) falls back to lobby.
|
||||
*/
|
||||
syncFromHistory(screen: AppScreen | undefined, gameId: string | null): void {
|
||||
const next =
|
||||
screen !== undefined && APP_SCREENS.includes(screen) ? screen : "lobby";
|
||||
this.#screen = next;
|
||||
this.#gameId = next === "game" ? gameId : null;
|
||||
persist();
|
||||
}
|
||||
|
||||
// Mirror the screen into browser history via shallow routing (the URL is
|
||||
// unchanged — the address bar stays at /game/). Overlays (game,
|
||||
// lobby-create) push a new entry so browser Back returns to the lobby
|
||||
// beneath; lobby/login replace in place.
|
||||
#syncHistory(): void {
|
||||
if (typeof window === "undefined") return;
|
||||
const state: App.PageState = { screen: this.#screen, gameId: this.#gameId };
|
||||
if (this.#screen === "game" || this.#screen === "lobby-create") {
|
||||
pushState("", state);
|
||||
} else {
|
||||
replaceState("", state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user