feat(plex): on-screen ±10s skip buttons flanking play/pause (E6 S3)
Add discoverable rewind-10 / forward-10 controls to the Plex player control bar, flanking play/pause (D5-A). New Skip10 glyph: an outline circular arrow with a centred '10', deliberately distinct from the episode-level SkipBack/SkipForward and from Restart's plain RotateCcw. Reuses seekTo; mirrors the keyboard ←/→ (seekStep=10). i18n HU/EN aria-labels.
This commit is contained in:
@@ -38,7 +38,7 @@ import {
|
||||
subShadowCss,
|
||||
type PlexPlayerPrefs,
|
||||
} from "../lib/plexPlayerPrefs";
|
||||
import { Ctrl, PanelHead } from "./plexPlayerControls";
|
||||
import { Ctrl, PanelHead, Skip10 } from "./plexPlayerControls";
|
||||
import { PlexPlayerSettings } from "./PlexPlayerSettings";
|
||||
import {
|
||||
useAutoSkip,
|
||||
@@ -936,9 +936,19 @@ export default function PlexPlayer({ itemId, onClose, queue }: Props) {
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3 text-white">
|
||||
<Ctrl label={t("plex.player.playPause")} onClick={togglePlay} align="start">
|
||||
<Ctrl
|
||||
label={t("plex.player.rewind10")}
|
||||
onClick={() => seekTo(absRef.current - 10)}
|
||||
align="start"
|
||||
>
|
||||
<Skip10 dir="back" />
|
||||
</Ctrl>
|
||||
<Ctrl label={t("plex.player.playPause")} onClick={togglePlay}>
|
||||
{playing ? <Pause className="w-6 h-6" /> : <Play className="w-6 h-6" />}
|
||||
</Ctrl>
|
||||
<Ctrl label={t("plex.player.forward10")} onClick={() => seekTo(absRef.current + 10)}>
|
||||
<Skip10 dir="forward" />
|
||||
</Ctrl>
|
||||
<Ctrl label={t("plex.player.restart")} onClick={() => seekTo(0)}>
|
||||
<RotateCcw className="w-5 h-5" />
|
||||
</Ctrl>
|
||||
|
||||
@@ -1,6 +1,49 @@
|
||||
import { type ReactNode } from "react";
|
||||
import { RotateCcw } from "lucide-react";
|
||||
|
||||
// ±10s skip glyph: an outline circular arrow with a "10" in the centre — the YouTube/Plex-native
|
||||
// muscle-memory shape. Deliberately distinct from the episode-level SkipBack/SkipForward (double
|
||||
// triangles) and from Restart's plain RotateCcw. The arrowhead is an L-corner at the arc's open end,
|
||||
// the same construction lucide uses for RotateCcw/RotateCw, so it sits consistently in the bar.
|
||||
export function Skip10({ dir }: { dir: "back" | "forward" }) {
|
||||
const back = dir === "back";
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="w-6 h-6"
|
||||
aria-hidden="true"
|
||||
>
|
||||
{back ? (
|
||||
<>
|
||||
<path d="M4 8.5 A8 8 0 1 1 4 12" />
|
||||
<path d="M4 8.5 L4 4 M4 8.5 L8.5 8.5" />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<path d="M20 8.5 A8 8 0 1 0 20 12" />
|
||||
<path d="M20 8.5 L20 4 M20 8.5 L15.5 8.5" />
|
||||
</>
|
||||
)}
|
||||
<text
|
||||
x="12"
|
||||
y="14.5"
|
||||
textAnchor="middle"
|
||||
fontSize="8"
|
||||
fontWeight={700}
|
||||
fill="currentColor"
|
||||
stroke="none"
|
||||
>
|
||||
10
|
||||
</text>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
// --- settings-panel building blocks ------------------------------------------------------------
|
||||
export function PanelHead({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
|
||||
@@ -160,6 +160,8 @@
|
||||
"skipCredits": "Skip credits",
|
||||
"playPause": "Play / pause (space)",
|
||||
"restart": "Restart from beginning",
|
||||
"rewind10": "Back 10 seconds",
|
||||
"forward10": "Forward 10 seconds",
|
||||
"prev": "Previous episode",
|
||||
"next": "Next episode",
|
||||
"mute": "Mute (m)",
|
||||
|
||||
@@ -160,6 +160,8 @@
|
||||
"skipCredits": "Stáblista átugrása",
|
||||
"playPause": "Lejátszás / szünet (szóköz)",
|
||||
"restart": "Újra az elejéről",
|
||||
"rewind10": "10 másodperc vissza",
|
||||
"forward10": "10 másodperc előre",
|
||||
"prev": "Előző rész",
|
||||
"next": "Következő rész",
|
||||
"mute": "Némítás (m)",
|
||||
|
||||
Reference in New Issue
Block a user