feat(appsession): mode switches never reload the iframe + strictly per-app display modes + TV focus

- The session subtree now ALWAYS lives under <body>; inline panel mode is
  emulated with a fixed-position rect synced from the layout placeholder
  (ResizeObserver + resize), so toggling panel/overlay/fullscreen no longer
  re-parents — and therefore no longer reloads — the app iframe.
- Display modes are strictly per-app: saved per-app pick → app default
  (IndeeHub: fullscreen) → panel. The global fallback is gone, so one app's
  mode can never change how another opens.
- The iframe takes focus when the app loads, so keyboard / the gamepad
  bridge work inside it immediately (TV).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-07-23 16:15:43 -04:00
co-authored by Claude Fable 5
parent 80875a2ed4
commit 402183c0ae
2 changed files with 71 additions and 12 deletions
@@ -9,19 +9,18 @@ export const DISPLAY_MODE_KEY = 'archipelago_app_display_mode'
/** Per-app default display mode. Used when the user hasn't explicitly picked
* a mode for that app (an explicit pick is remembered per app and wins).
* Apps not listed fall back to the last globally-used mode, then 'panel'. */
* Apps not listed default to 'panel'. */
export const APP_DEFAULT_DISPLAY_MODE: Record<string, DisplayMode> = {
'indeedhub': 'fullscreen',
}
/** Initial display mode for an app session: per-app user choice → per-app
* default → last global choice → panel. */
* default → panel. Strictly per-app — deliberately NO global fallback, so
* one app's mode change can never affect how another app opens. */
export function initialDisplayMode(id: string): DisplayMode {
const perApp = localStorage.getItem(`${DISPLAY_MODE_KEY}:${id}`) as DisplayMode | null
if (perApp === 'panel' || perApp === 'overlay' || perApp === 'fullscreen') return perApp
const appDefault = APP_DEFAULT_DISPLAY_MODE[id]
if (appDefault) return appDefault
return (localStorage.getItem(DISPLAY_MODE_KEY) as DisplayMode) || 'panel'
return APP_DEFAULT_DISPLAY_MODE[id] ?? 'panel'
}
/** Container apps: manifest-generated launch ports plus overrides for companions and aliases. */