Add crew/player/rat name to page title

Each routed page now sets a descriptive document.title so tabs and
browser history entries are distinguishable: the dashboard shows the
Pi-Rat (and human player) name plus crew, the admin panel shows
"Admin · {crew}", the join page is labeled, and home resets to the
app name. New lib/title.js helper composes "{parts} — Rats with Gats".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 21:09:36 -07:00
parent fb17c632b0
commit d68333ec05
6 changed files with 25 additions and 1 deletions

View File

@@ -5,7 +5,6 @@
## Minor Gameplay Polish ## Minor Gameplay Polish
- [ ] **Add crew/player/rat name to page title, if available**. This will make it easier to distinguish tabs/browser history entries
- [ ] **Save active sessions in browser local storage**. Whenever you create or join a game, your browser local storage should be updated with the game ID, player ID, crew name, and player/rat names (if available). Going to the home page with saved sessions should provide a menu of games to rejoin in addition to the ability to start a new game. It should be possible to delete entries from this list, which only affects the browser local storage, not the backend database, and is undoable (the entry doesn't disappear immediately, it's just marked as deleted until page refresh). - [ ] **Save active sessions in browser local storage**. Whenever you create or join a game, your browser local storage should be updated with the game ID, player ID, crew name, and player/rat names (if available). Going to the home page with saved sessions should provide a menu of games to rejoin in addition to the ability to start a new game. It should be possible to delete entries from this list, which only affects the browser local storage, not the backend database, and is undoable (the entry doesn't disappear immediately, it's just marked as deleted until page refresh).
- [ ] **Dead Pi-Rat rank voting streamlined**. Don't allow voting for dead Pi-Rats. If a player's only vote options are dead, then they skip voting entirely. - [ ] **Dead Pi-Rat rank voting streamlined**. Don't allow voting for dead Pi-Rats. If a player's only vote options are dead, then they skip voting entirely.

View File

@@ -0,0 +1,9 @@
// Sets document.title to a " · "-joined set of page specifics followed by the
// app name, so tabs and browser history entries are easy to tell apart.
// Falsy parts are dropped; with no parts the title is just the app name.
const BASE = 'Rats with Gats';
export function setPageTitle(...parts) {
const prefix = parts.filter(Boolean).join(' · ');
document.title = prefix ? `${prefix}${BASE}` : BASE;
}

View File

@@ -1,6 +1,7 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { apiRequest } from '../lib/api'; import { apiRequest } from '../lib/api';
import { setPageTitle } from '../lib/title';
export let params = {}; export let params = {};
let gameId = params.id; let gameId = params.id;
@@ -13,6 +14,8 @@
let copiedInvite = false; let copiedInvite = false;
let copiedInviteTimer = null; let copiedInviteTimer = null;
$: setPageTitle('Admin', data?.game?.crew_name);
function rejoinLink(playerId) { function rejoinLink(playerId) {
return `${window.location.origin}/#/game/${gameId}/player/${playerId}`; return `${window.location.origin}/#/game/${gameId}/player/${playerId}`;
} }

View File

@@ -3,6 +3,8 @@
import { apiRequest } from '../lib/api'; import { apiRequest } from '../lib/api';
import { extraMenuLinks } from '../lib/menu'; import { extraMenuLinks } from '../lib/menu';
import { getSuggestion } from '../lib/suggestions'; import { getSuggestion } from '../lib/suggestions';
import { displayName } from '../lib/cards';
import { setPageTitle } from '../lib/title';
import LobbyPhase from '../components/LobbyPhase.svelte'; import LobbyPhase from '../components/LobbyPhase.svelte';
import CharacterCreationPhase from '../components/CharacterCreationPhase.svelte'; import CharacterCreationPhase from '../components/CharacterCreationPhase.svelte';
@@ -103,6 +105,9 @@
} }
} }
// Distinguish tabs/history by the Pi-Rat (and crew) this dashboard is for
$: setPageTitle(state ? displayName(state.player) : null, state?.game?.crew_name);
// Admins get the admin key in their state blob; stash it so the Admin page works for them too // Admins get the admin key in their state blob; stash it so the Admin page works for them too
$: if (state?.player?.is_admin && state?.game?.admin_key) { $: if (state?.player?.is_admin && state?.game?.admin_key) {
localStorage.setItem(`admin_key_${gameId}`, state.game.admin_key); localStorage.setItem(`admin_key_${gameId}`, state.game.admin_key);

View File

@@ -1,6 +1,10 @@
<script> <script>
import { onMount } from 'svelte';
import { push } from 'svelte-spa-router'; import { push } from 'svelte-spa-router';
import { apiRequest } from '../lib/api'; import { apiRequest } from '../lib/api';
import { setPageTitle } from '../lib/title';
onMount(() => setPageTitle());
let crewName = ''; let crewName = '';
let error = ''; let error = '';

View File

@@ -1,7 +1,11 @@
<script> <script>
import { onMount } from 'svelte';
import { push } from 'svelte-spa-router'; import { push } from 'svelte-spa-router';
import { apiRequest } from '../lib/api'; import { apiRequest } from '../lib/api';
import { setPageTitle } from '../lib/title';
export let params = {}; export let params = {};
onMount(() => setPageTitle('Join the Crew'));
let gameId = params.id; let gameId = params.id;
let playerName = ''; let playerName = '';
let error = ''; let error = '';