feat(e24): reach the Home surface — the landing toggle, a palette command, Shift+W

S4's reachability half. Home already led the nav order; what was missing was every
way IN other than the rail.

- Settings → Appearance → Startup: "Start on Home", the documented escape hatch for
  the landing override. Deliberately still localStorage and not a server pref —
  `loadInitialPage` answers before /api/me lands, and a landing module decided after
  the first paint is a visible jump. Its two stored values are now ONE exported
  constant, so the writer and the boot-time reader cannot drift on a magic string.
- The command palette gets "Meglepetés" / "Surprise me": it navigates to Home and
  rerolls the hero on arrival. No second "Mit nézzek?" row beside it — the Home
  module row already matches that phrase through its descriptive title.
- A global Shift+W jumps to Home. A chord, not a bare `w`: the Plex player binds bare
  letters and `w` sits on `s`, so a blind reach for the subtitle key would have thrown
  a viewer out of the film.

The palette's request crosses a lazy module boundary, so it is a token that waits
(lib/homeIntent) rather than an event fired into an empty room. Browser-measured:
taken with a compare-and-clear, because StrictMode's double-invoked mount effect
otherwise rerolled twice and landed on the page two picks deep.

HU/EN parity kept; UAT on localdev in both languages, including the empty shelf.
This commit is contained in:
2026-09-08 00:06:34 +02:00
parent 82914b56ca
commit 828dad015c
18 changed files with 238 additions and 29 deletions
+11 -4
View File
@@ -6,10 +6,16 @@ import { hasFilterParams, isPage, readPage, type Page } from "../lib/urlState";
import { getAccountRaw, LS } from "../lib/storage";
export const PAGE_KEY = LS.page;
// Module-local: the Settings opt-out (S4) writes `LS.startOnHome` directly, so exporting this
// alias would only be a second name for the same key.
// Module-local: the Settings toggle writes `LS.startOnHome` directly, so exporting this alias would
// only be a second name for the same key.
const START_HOME_KEY = LS.startOnHome;
/** The two stored values of the landing preference (raw strings, via useAccountPersistedState).
* Settings → Appearance → Startup writes them and `loadInitialPage` reads them, so they are defined
* ONCE: the same magic string spelled out in a writer and a reader is precisely the drift that has
* bitten this codebase before (`cancelled` vs `canceled`). */
export const START_ON_HOME = { on: "1", off: "0" } as const;
export interface ChannelView {
id: string;
name?: string;
@@ -26,8 +32,9 @@ export function loadInitialPage(): Page {
// A bare URL → Home (E24), the surface whose whole job is to answer "what should I watch" before
// the user has to decide anything. It deliberately OVERRIDES the remembered last module: landing
// on whatever you happened to close the app on is the behaviour the anti-paralysis epic exists to
// replace. The account can opt out (Settings) and get the remembered module back.
if (getAccountRaw(START_HOME_KEY) !== "0") return "home";
// replace. The account can opt out (Settings → Appearance → Startup) and get the remembered
// module back.
if (getAccountRaw(START_HOME_KEY) !== START_ON_HOME.off) return "home";
const stored = getAccountRaw(PAGE_KEY);
return isPage(stored) ? stored : "feed";
}