diff --git a/docs/DESIGN.md b/docs/DESIGN.md index df11803a..486a228e 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -713,3 +713,4 @@ of a full-width panel and nothing on the right. | 2026-10-06 | `player` focus | A dialog that is a player opens focused on its panel (the YouTube player's rule, now `Modal`'s too); on the media element itself, Space and the arrows stay the element's own | `close`, or the media element | On the ✕ Space closed the player; on the element the browser's own controls acted on the same key as the player's (one Space played and paused, measured in Chrome) | | 2026-10-08 | Captions on touch | A `Tooltip` opens for a mouse and a key's focus only, never for a finger | A caption on tap; a long-press caption | On an iPad the tap that showed the caption was taken as a hover and lost its click (every rail button took two taps), and no finger sends the mouseleave that hides it; the rail's labels setting names the buttons on touch | | 2026-10-08 | Header search on touch | No key cap on a touch screen; the pill grows to 52 px so a ring shows round the 44 px Go; Go drops to its icon by the column's width | Keep the key cap; a 44 px Go overhanging a 40 px pill | On a tablet the 44 px key cap and Go sat on the pill's edge and cut the placeholder; an overhanging Go breaks the nested radii | +| 2026-10-08 | Plex subtitles and the control bar | The player draws the cues itself; while the bar shows they rise above it (200 ms), then settle back | The browser's own cues, moved by `line` | On an iPad the bar covered the text; a native cue cannot be animated or measured, and our layer behaves the same on every engine | diff --git a/frontend/src/components/PlexPlayer.tsx b/frontend/src/components/PlexPlayer.tsx index 1c84e3b9..3ec37ba0 100644 --- a/frontend/src/components/PlexPlayer.tsx +++ b/frontend/src/components/PlexPlayer.tsx @@ -45,7 +45,6 @@ import { DEFAULT_PREFS, fmt, subOrdForLang, - subShadowCss, type PlexPlayerPrefs, } from "../lib/plexPlayerPrefs"; import { Ctrl, PanelHead } from "./plexPlayerControls"; @@ -84,6 +83,7 @@ import { LS, useAccountPersistedObject } from "../lib/storage"; import { useDismiss } from "../lib/useDismiss"; import { useScrollFade } from "../lib/useScrollFade"; import { useBackToClose } from "../lib/history"; +import PlexSubtitles from "./PlexSubtitles"; import { lockBodyScroll, trapTab } from "./ui/dialogFocus"; import { pushLayer, @@ -150,6 +150,8 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false } const videoRef = useRef(null); const wrapRef = useRef(null); + // The bottom band, which the subtitles keep above while it shows. + const bottomBarRef = useRef(null); // A control that goes while it holds the focus — Next onto the last item or a series finale — // hands it to its neighbour instead of . The player is portaled outside the // page scroller, whose keeper does not watch it. @@ -418,7 +420,6 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false } detail, sessionK, subOffset: prefs.subOffset, - subPos: prefs.subPos, restartSession, setAudioTrack: (track: number) => engine.setAudioTrack(track), patchPrefs, @@ -1130,12 +1131,6 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false } }), }} > - {/* Per-user subtitle appearance (font size / colour / background). ::cue is global, but this - player owns the only