Play: make Back step through the game screens (URL-driven views)
The Hub → Game Selection → Game screens were internal $state with no history entries, so the device/browser Back button skipped straight out of /play. Now the screen is derived from the URL (?game=…&v=…) and forward moves use goto, so each screen is a real history entry: Back goes Game → Selection → Hub → site, matching the rest of the app. The in-app Back button uses history.back() so it mirrors the device button. Statuses refresh on every navigation (incl. Back). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,20 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import { goto, afterNavigate } from '$app/navigation';
|
||||||
|
import { page } from '$app/stores';
|
||||||
import { getJSON } from '$lib/api.js';
|
import { getJSON } from '$lib/api.js';
|
||||||
import WordGame from '$lib/components/WordGame.svelte';
|
import WordGame from '$lib/components/WordGame.svelte';
|
||||||
import WordSearchGame from '$lib/components/WordSearchGame.svelte';
|
import WordSearchGame from '$lib/components/WordSearchGame.svelte';
|
||||||
|
|
||||||
let view = $state('hub'); // 'hub' | 'select' | 'play'
|
// Screen is derived from the URL so the device/browser Back button steps through
|
||||||
let game = $state('word'); // 'word' | 'wordsearch'
|
// Hub → Game Selection → Game (each screen is its own history entry), instead of
|
||||||
let variant = $state('5');
|
// jumping straight out of /play.
|
||||||
let wsSize = $state('med');
|
let sp = $derived($page.url.searchParams);
|
||||||
|
let game = $derived(sp.get('game') === 'wordsearch' ? 'wordsearch' : 'word');
|
||||||
|
let view = $derived(!sp.get('game') ? 'hub' : (sp.get('v') ? 'play' : 'select'));
|
||||||
|
let variant = $derived(sp.get('v') || '5');
|
||||||
|
let wsSize = $derived(sp.get('v') || 'med');
|
||||||
|
|
||||||
let date = $state('');
|
let date = $state('');
|
||||||
let wordStatus = $state({ 5: null, 6: null });
|
let wordStatus = $state({ 5: null, 6: null });
|
||||||
let wsStatus = $state(null);
|
let wsStatus = $state(null);
|
||||||
@@ -71,8 +78,11 @@
|
|||||||
return 'Play';
|
return 'Play';
|
||||||
}
|
}
|
||||||
|
|
||||||
function openGame(g) { game = g; view = 'select'; refreshStatus(); }
|
// Forward navigations push a history entry (via goto); the in-app Back button
|
||||||
function pick(v) { if (game === 'word') variant = v; else wsSize = v; view = 'play'; }
|
// pops it (history.back), so it mirrors the device Back button exactly.
|
||||||
|
function openGame(g) { goto('/play?game=' + g); }
|
||||||
|
function pick(v) { goto('/play?game=' + game + '&v=' + v); }
|
||||||
|
function back() { history.back(); }
|
||||||
|
|
||||||
// Daily Word on mobile = a focused viewport: lock scroll + hide footer. Cleanup
|
// Daily Word on mobile = a focused viewport: lock scroll + hide footer. Cleanup
|
||||||
// ALWAYS removes the class (re-run or unmount), so leaving /play can't strand it.
|
// ALWAYS removes the class (re-run or unmount), so leaving /play can't strand it.
|
||||||
@@ -83,10 +93,6 @@
|
|||||||
return () => document.documentElement.classList.remove('playing-word');
|
return () => document.documentElement.classList.remove('playing-word');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
function back() {
|
|
||||||
view = view === 'play' ? 'select' : 'hub';
|
|
||||||
refreshStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
const WS_OPTS = [
|
const WS_OPTS = [
|
||||||
['small', 'Small', 'cosy · 8×8'],
|
['small', 'Small', 'cosy · 8×8'],
|
||||||
@@ -98,6 +104,8 @@
|
|||||||
try { date = (await getJSON('/api/puzzle/word?variant=5')).date; } catch { /* offline */ }
|
try { date = (await getJSON('/api/puzzle/word?variant=5')).date; } catch { /* offline */ }
|
||||||
refreshStatus();
|
refreshStatus();
|
||||||
});
|
});
|
||||||
|
// Refresh hub/selection statuses whenever we land on a screen (incl. Back).
|
||||||
|
afterNavigate(() => refreshStatus());
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head><title>Play · Upbeat Bytes</title></svelte:head>
|
<svelte:head><title>Play · Upbeat Bytes</title></svelte:head>
|
||||||
|
|||||||
Reference in New Issue
Block a user