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:
2026-11-01 18:26:33 +01:00
parent b3402d158f
commit 8dd2f0c015
37 changed files with 457 additions and 243 deletions
@@ -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 (
<>