import { Fragment } from "react"; import { useTranslation } from "react-i18next"; import Modal from "./Modal"; import { closeKeyboardHelp, formatChord, helpLines, isPageLevelScope, useActiveScopes, useHelpConditionValues, useKeyboardHelpOpen, useKeyboardHelpOverLayer, useNavigablePages, } from "../../lib/keymap"; // The app's one keyboard cheat sheet. Mounted once by App; the global `h` that opens it lives in // `useGlobalKeymap`, beside the palette's Mod+K, so one listener owns the whole `global` scope. // // It renders the shared SHORTCUTS table filtered to the scopes that are live right now — the Plex // player's keys while you are in the player, the app-wide ones underneath — so there is a single // answer to "what can I press here" and nothing to keep in sync. Before this, the Plex player had a // cheat sheet nobody else did, listing an array hand-copied from its own handler. // // `h` rather than the conventional `?`: on a Hungarian layout `?` is a Shift chord, and `h` is the // key this app's reader already has in their fingers from the player. // // Deliberately NOT a new overlay primitive: `Modal` already portals into // `document.fullscreenElement ?? document.body` (so this works over a fullscreen player), registers // a layer so Escape closes it before the player underneath, traps focus and handles browser Back. export default function KeyboardHelp() { const { t } = useTranslation(); const open = useKeyboardHelpOpen(); const scopes = useActiveScopes(); const conditions = useHelpConditionValues(); const overLayer = useKeyboardHelpOverLayer(); const pages = useNavigablePages(); if (!open) return null; // A `when` row is listed only where it applies — "Previous / next episode" inside a movie would be // a promise the player does not keep. // Opened over a player or a dialog, the page-level keys (`s`, `g …`, `j`/`k`) are quiet — listing // them there would promise keys that do nothing until the overlay closes. And a `g` chord is listed // only for a module this account can actually reach. // The context-menu key goes too: every `useContextMenu` is a page list, and with an overlay up the // focus Shift+F10 needs is inside the overlay (pre-existing since E10, found in S4 UAT). const live = overLayer ? scopes.filter((s) => !isPageLevelScope(s) && s !== "contextMenu") : scopes; const lines = helpLines(live, pages).filter((l) => !l.when || !!conditions[l.when]); const words = { Space: t("keys.cap.space"), ContextMenu: t("keys.cap.menu") }; return (
{lines.map((line) => (
{line.chords.map((chord) => ( {formatChord(chord, words)} ))}
{t(line.labelKey)}
))}
); }