dynamic per-route + per-subdomain document titles (0.71.0)

- the SPA had one static title, so every tavern route and the docs/pm
  subdomains all read 'amerc — hire agents like mercenaries' in the tab
- tavern now sets a descriptive title per route (Browse Agents · amerc,
  System status · amerc, etc.); docs/pm set 'Docs · amerc' / 'PM · amerc'
- clearer browser tabs, bookmarks and history
- verified live across home/agents/status + docs + pm
This commit is contained in:
artheru 2026-06-10 09:36:44 +08:00
parent 6d54d89a0b
commit 696d727e44
4 changed files with 11 additions and 5 deletions

View File

@ -4,7 +4,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#0e0a14" /> <meta name="theme-color" content="#0e0a14" />
<meta name="description" content="amerc is the agent mercenary tavern — hire, run, publish, and remotely deliver AI agents across software boundaries. No infrastructure, just skills." /> <meta name="description" content="amerc is the agent mercenary tavern — hire, run, publish, and remotely deliver AI agents across software boundaries. No infrastructure, just skills." />
<meta name="version" content="0.70.0-mobilemenu" /> <meta name="version" content="0.71.0-titles" />
<link rel="icon" href="/favicon.svg" type="image/svg+xml" /> <link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="icon" href="/app-192.png" type="image/png" sizes="192x192" /> <link rel="icon" href="/app-192.png" type="image/png" sizes="192x192" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" /> <link rel="apple-touch-icon" href="/apple-touch-icon.png" />

View File

@ -1,6 +1,6 @@
{ {
"name": "amerc-site", "name": "amerc-site",
"version": "0.70.0-mobilemenu", "version": "0.71.0-titles",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {

View File

@ -7,7 +7,7 @@ import Account from './Account.jsx';
import TavernGame from './TavernGame.jsx'; import TavernGame from './TavernGame.jsx';
import { api } from './api.js'; import { api } from './api.js';
const RELEASE = '0.70.0-mobilemenu'; const RELEASE = '0.71.0-titles';
const NAV = [ const NAV = [
{ id: 'home', label: 'Tavern' }, { id: 'home', label: 'Tavern' },
@ -16,6 +16,11 @@ const NAV = [
{ id: 'booth', label: 'My Booth' }, { id: 'booth', label: 'My Booth' },
]; ];
const VALID_ROUTES = ['home', 'agents', 'mansion', 'booth', 'account', 'admin', 'signin', 'status', 'changelog']; const VALID_ROUTES = ['home', 'agents', 'mansion', 'booth', 'account', 'admin', 'signin', 'status', 'changelog'];
const ROUTE_TITLES = {
home: 'amerc — hire agents like mercenaries', agents: 'Browse Agents · amerc', mansion: 'The Mansion · amerc',
booth: 'My Booth · amerc', account: 'Account · amerc', signin: 'Sign in · amerc', status: 'System status · amerc',
changelog: 'Changelog · amerc', admin: 'Quartermaster · amerc',
};
function useHashRoute() { function useHashRoute() {
const normalize = () => { const normalize = () => {
@ -451,6 +456,7 @@ export default function Scene2DApp() {
const [route, setRoute] = useHashRoute(); const [route, setRoute] = useHashRoute();
const auth = useAuth(); const auth = useAuth();
const isHome = route === 'home'; const isHome = route === 'home';
useEffect(() => { document.title = ROUTE_TITLES[route] || 'amerc'; }, [route]);
return ( return (
<main className="px-app td-app"> <main className="px-app td-app">
<h1 className="sr-only">amerc agent mercenary tavern</h1> <h1 className="sr-only">amerc agent mercenary tavern</h1>

View File

@ -9,8 +9,8 @@ const PmApp = lazy(() => import('./PmApp.jsx'));
const Scene2DApp = lazy(() => import('./Scene2D.jsx')); const Scene2DApp = lazy(() => import('./Scene2D.jsx'));
let App = Scene2DApp; let App = Scene2DApp;
if (host.startsWith('docs.')) App = DocsApp; if (host.startsWith('docs.')) { App = DocsApp; document.title = 'Docs · amerc'; }
else if (host.startsWith('pm.')) App = PmApp; else if (host.startsWith('pm.')) { App = PmApp; document.title = 'PM · amerc'; }
// Preload the tavern's canvas tiles on the main domain so the scene paints as // Preload the tavern's canvas tiles on the main domain so the scene paints as
// soon as the app mounts they download in parallel with the JS chunk instead // soon as the app mounts they download in parallel with the JS chunk instead