fix: review round 2 — Clear watch progress clears only the resume point, big view focus by the way it arrived, dialog name, reason tooltip, backfill locks
This commit is contained in:
@@ -4,6 +4,7 @@ import { ListEnd, ListStart, Repeat, Repeat1, Shuffle, SkipBack, SkipForward } f
|
||||
import type { VideoDetail } from "../../lib/api";
|
||||
import type { AutoMode, LoopMode } from "../../lib/playerModes";
|
||||
import { IconButton } from "../../components/ui/IconButton";
|
||||
import Tooltip from "../../components/ui/Tooltip";
|
||||
import { StateMessage } from "../../components/ui/QueryState";
|
||||
import { unavailable } from "../../components/ui/unavailable";
|
||||
import { ClampedText } from "../../components/ui/ClampedText";
|
||||
@@ -13,6 +14,25 @@ import { renderDescription } from "./descriptionLinks";
|
||||
// the sibling of plexPlayerControls.tsx. No state or effects here; all behaviour comes in via props.
|
||||
// The auto-advance / loop modes it renders are defined in `lib/playerModes`.
|
||||
|
||||
/** Why a control is off, where a key's focus reads it too: a browser's own tooltip (`title`, left on
|
||||
* the button for what it does) shows for a mouse alone. `stable`: the reason comes and goes under a
|
||||
* control that may hold the focus. */
|
||||
export function ReasonTooltip({
|
||||
reason,
|
||||
side,
|
||||
children,
|
||||
}: {
|
||||
reason: string | undefined;
|
||||
side?: "left";
|
||||
children: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<Tooltip hint={reason ?? ""} always={!!reason} side={side} stable>
|
||||
{children}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
/** The queue transport cluster — prev / counter / next, then the auto-advance and loop modes.
|
||||
* Rendered in two places from ONE list of controls: the modal's queue bar (`variant:"modal"`, normal
|
||||
* glass theme) and the big-view docked control bar (`variant:"docked"`, white-on-dark). Glyphs only
|
||||
@@ -60,7 +80,7 @@ export function PlayerTransportControls({
|
||||
const docked = variant === "docked";
|
||||
// Never broken or squeezed: in a row that scrolls, a squeezed "1 / 55" stood on three lines.
|
||||
const counter = `shrink-0 whitespace-nowrap tabular-nums ${docked ? "text-white/70" : "text-muted"}`;
|
||||
const divider = docked ? "h-4 w-px bg-white/20" : "w-px h-4 bg-border";
|
||||
const divider = `h-4 w-px shrink-0 ${docked ? "bg-white/20" : "bg-border"}`;
|
||||
const autoName = `${t("player.autoAdvance.label")}: ${t(`player.autoAdvance.${autoMode}`)}`;
|
||||
const loopName = `${t("player.loop.label")}: ${t(`player.loop.${loopMode}`)}`;
|
||||
type Control = {
|
||||
@@ -114,17 +134,18 @@ export function PlayerTransportControls({
|
||||
},
|
||||
];
|
||||
const render = (c: Control) => (
|
||||
<IconButton
|
||||
key={c.key}
|
||||
variant={docked ? "overlay" : undefined}
|
||||
onClick={c.onClick}
|
||||
{...unavailable(c.disabled, c.reason)}
|
||||
lit={c.lit}
|
||||
label={c.name}
|
||||
title={c.reason ? `${c.title} · ${c.reason}` : c.title}
|
||||
>
|
||||
{c.glyph}
|
||||
</IconButton>
|
||||
<ReasonTooltip key={c.key} reason={c.reason}>
|
||||
<IconButton
|
||||
variant={docked ? "overlay" : undefined}
|
||||
onClick={c.onClick}
|
||||
{...unavailable(c.disabled, c.reason)}
|
||||
lit={c.lit}
|
||||
label={c.name}
|
||||
title={c.title}
|
||||
>
|
||||
{c.glyph}
|
||||
</IconButton>
|
||||
</ReasonTooltip>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user