feat(plex): subtitles rise above the control bar while it shows
On an iPad the bar covered the text whenever it was up: the browser places a native cue by its line, which nothing animates. The track now stays loaded as hidden and PlexSubtitles draws the active cues, measured against the bar and lifted above it in 200 ms, back down when it hides. The viewer's size, colour, background and outline settings style the text directly. Also fixes a test typing slip from the search pill change.
This commit is contained in:
@@ -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<HTMLVideoElement | null>(null);
|
||||
const wrapRef = useRef<HTMLDivElement>(null);
|
||||
// The bottom band, which the subtitles keep above while it shows.
|
||||
const bottomBarRef = useRef<HTMLDivElement>(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 <body>. 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 <video> on screen. */}
|
||||
<style>{`video::cue{font-size:${prefs.subSize}%;color:${prefs.subColor};background-color:${prefs.subBg};${subShadowCss(
|
||||
prefs.subShadow,
|
||||
prefs.subShadowColor,
|
||||
)}}`}</style>
|
||||
<video
|
||||
ref={(el) => {
|
||||
videoRef.current = el;
|
||||
@@ -1151,8 +1146,8 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
|
||||
onClick={onPictureClick}
|
||||
playsInline
|
||||
>
|
||||
{/* Text subtitles as native tracks (same-origin → sent with the session cookie). The effect
|
||||
above flips modes; the browser fetches a track's VTT the first time it's shown. */}
|
||||
{/* Text subtitles as a native track (same-origin → sent with the session cookie), kept
|
||||
`hidden`: the browser fetches and parses the VTT, PlexSubtitles below draws the cues. */}
|
||||
{selectedSub && subShowable && (
|
||||
<track
|
||||
// One track = the selected sub only (no multi-track overlap). The key (see usePlexTracks)
|
||||
@@ -1168,6 +1163,17 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
|
||||
/>
|
||||
)}
|
||||
</video>
|
||||
<PlexSubtitles
|
||||
video={videoEl}
|
||||
pos={prefs.subPos}
|
||||
size={prefs.subSize}
|
||||
color={prefs.subColor}
|
||||
background={prefs.subBg}
|
||||
shadowPx={prefs.subShadow}
|
||||
shadowColor={prefs.subShadowColor}
|
||||
avoid={uiVisible}
|
||||
avoidRef={bottomBarRef}
|
||||
/>
|
||||
|
||||
{/* Loading / buffering / error overlay. `!ready` = initial session load; `buffering` = a
|
||||
mid-playback stall or in-flight seek (see the state); `loadError` surfaces a fatal failure so
|
||||
@@ -1331,6 +1337,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
|
||||
|
||||
{/* Bottom controls */}
|
||||
<div
|
||||
ref={bottomBarRef}
|
||||
{...holdWhileHovered}
|
||||
className={`absolute bottom-0 inset-x-0 px-4 pb-3 pt-3 bg-linear-to-t from-black/80 to-transparent transition-opacity ${
|
||||
uiVisible
|
||||
|
||||
Reference in New Issue
Block a user