fix(keys): epic-end review round 3 — the part-way clip count shows, busy buttons keep focus, cards say their names
Targeted round over 3cd0c525's fix surfaces: 14 raised, 14 fixed. - VideoEditor: the "only X of Y clips" toast went silent exactly on the job-cap/quota refusal it was written for (req had already reported the error); it now always shows. The cut list holds still while Create queues, and a retry continues the "(i/N)" series. - ChannelPage: Subscribe/Unsubscribe use Button `loading`, "Load more" and ChannelDiscovery's Subscribe block the click with aria-disabled instead of native disabled; busy Block/Hide no longer light up on hover. - listNav: an item can name itself (`navItemAttrs(i, name)`) — Plex posters, seasons, episodes, message rows and download rows pass their title; focus on a toast's Undo keeps the removed card's slot. - AnchoredPopover: the hand-back only for focus-managed surfaces (a hover card no longer pulls focus back); the dead panel-ref check is gone. - AccountPanel: no confirmation mail offered to the demo account; send_failed copy no longer blames the message for an unreachable server. Pager comment points at scrollParent.
This commit is contained in:
@@ -481,14 +481,16 @@ export default function ChannelPage({
|
||||
<button
|
||||
// Busy blocks the click, not the focus: a focused button that turns natively
|
||||
// `disabled` drops the keyboard to <body> (the rule and its measurement: ui/Button).
|
||||
// Nor does a busy toggle light up on hover, as if a click would do something.
|
||||
onClick={() => !block.isPending && block.mutate()}
|
||||
aria-disabled={block.isPending || undefined}
|
||||
aria-busy={block.isPending || undefined}
|
||||
title={ch?.blocked ? t("channel.unblock") : t("channel.block")}
|
||||
aria-label={ch?.blocked ? t("channel.unblock") : t("channel.block")}
|
||||
className={`inline-flex items-center justify-center w-9 h-9 rounded-lg border aria-disabled:opacity-50 transition ${
|
||||
ch?.blocked
|
||||
? "border-danger text-danger"
|
||||
: "border-border text-muted hover:text-danger hover:border-danger"
|
||||
: "border-border text-muted not-aria-disabled:hover:text-danger not-aria-disabled:hover:border-danger"
|
||||
}`}
|
||||
>
|
||||
<Ban className="w-4 h-4" />
|
||||
@@ -501,12 +503,13 @@ export default function ChannelPage({
|
||||
<button
|
||||
onClick={() => !toggleHidden.isPending && toggleHidden.mutate()}
|
||||
aria-disabled={toggleHidden.isPending || undefined}
|
||||
aria-busy={toggleHidden.isPending || undefined}
|
||||
title={ch.hidden ? t("channel.hiddenHint") : t("channel.hideHint")}
|
||||
aria-label={ch.hidden ? t("channel.unhide") : t("channel.hide")}
|
||||
className={`inline-flex items-center justify-center w-9 h-9 rounded-lg border aria-disabled:opacity-50 transition ${
|
||||
ch.hidden
|
||||
? "border-accent text-accent"
|
||||
: "border-border text-muted hover:text-fg hover:border-fg/40"
|
||||
: "border-border text-muted not-aria-disabled:hover:text-fg not-aria-disabled:hover:border-fg/40"
|
||||
}`}
|
||||
>
|
||||
{ch.hidden ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
|
||||
@@ -518,7 +521,7 @@ export default function ChannelPage({
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={onUnsubscribe}
|
||||
disabled={unsubscribe.isPending}
|
||||
loading={unsubscribe.isPending}
|
||||
title={t("channel.unsubscribe")}
|
||||
icon={<Check className="w-4 h-4" />}
|
||||
>
|
||||
@@ -528,7 +531,7 @@ export default function ChannelPage({
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => subscribe.mutate()}
|
||||
disabled={subscribe.isPending}
|
||||
loading={subscribe.isPending}
|
||||
icon={<Plus className="w-4 h-4" />}
|
||||
>
|
||||
{t("channel.subscribe")}
|
||||
@@ -575,9 +578,11 @@ export default function ChannelPage({
|
||||
{!ch?.subscribed && nextToken && (
|
||||
<div className="flex justify-center pb-6">
|
||||
<button
|
||||
onClick={() => runExplore(nextToken)}
|
||||
disabled={exploring}
|
||||
className="inline-flex items-center gap-2 px-4 py-2 rounded-lg text-sm border border-border hover:bg-surface disabled:opacity-50"
|
||||
// Busy blocks the click, not the focus (see Block above).
|
||||
onClick={() => !exploring && runExplore(nextToken)}
|
||||
aria-disabled={exploring || undefined}
|
||||
aria-busy={exploring || undefined}
|
||||
className="inline-flex items-center gap-2 px-4 py-2 rounded-lg text-sm border border-border not-aria-disabled:hover:bg-surface aria-disabled:opacity-50"
|
||||
>
|
||||
{exploring ? (
|
||||
<Loader2 className="w-4 h-4 animate-spin" />
|
||||
|
||||
Reference in New Issue
Block a user