fix(player): the shut panel keeps the dialog's name; Tab onto a cut link opens the text

With the side panel shut the title heading was gone, and the dialog it named
went unnamed: the strip carries an sr-only copy. A link below a clamp's cut
stayed tabbable out of sight; reaching it now opens the text, measured from the
text's top since focus scrolls the clamped box. DESIGN describes the modal as
built, with log rows for its chrome and the wheel rule.
This commit is contained in:
2026-10-09 22:01:27 +02:00
parent 76738f8ea9
commit 5572499b56
5 changed files with 175 additions and 117 deletions
+7 -1
View File
@@ -324,6 +324,8 @@ export default function PlayerModal({
const navigated = currentVideoId !== active.id;
// Title/author of a navigated-to video, read from the player (free, no API call).
const [liveData, setLiveData] = useState<{ title?: string; author?: string } | null>(null);
// What is playing, by name: the panel's title, and the dialog's name (`titleId`) in either layout.
const heading = navigated ? (liveData?.title ?? t("player.loading")) : active.title;
// IFrame Player API error code, when the current video can't play in the embed (e.g. an
// auto-generated Topic "Art Track" with embedding disabled → 101/150, or removed/private →
// 100). We overlay a friendly message + "Open on YouTube" instead of YouTube's bare error.
@@ -919,6 +921,10 @@ export default function PlayerModal({
data-testid="player-strip"
className="absolute inset-0 flex flex-col items-center gap-1 py-2"
>
{/* The dialog is named by this heading's id: the panel's own one is not rendered. */}
<h2 id={titleId} className="sr-only">
{heading}
</h2>
{closeButton}
<IconButton
ref={panelToggleRef}
@@ -995,7 +1001,7 @@ export default function PlayerModal({
right (wide, it heads the panel). */}
<div className="flex items-start gap-3">
<h2 id={titleId} className="min-w-0 flex-1 text-lg font-semibold leading-snug">
{navigated ? (liveData?.title ?? t("player.loading")) : active.title}
{heading}
</h2>
{!wide && (
<IconButton