fix(playlists): address the review round — 11 findings

Header (shared, so every table gets these):
- The filter funnel could not close itself: useDismiss only knew the panel, so
  the trigger's mousedown closed it and the click reopened it. It now knows the
  trigger, captured at open time so it survives the close.
- Escape stranded focus on <body>; it goes back to the funnel, which also gained
  aria-expanded/aria-haspopup.
- A non-sortable header rendered a focusable no-op button — two unlabeled dead
  stops per playlist table, whose grip and actions headers are empty. Plain span
  unless the column sorts.

Playlist:
- The disabled drag grip explained itself to nobody: `disabled` drops a button
  from the tab order and suppresses its tooltip. It is aria-disabled now, stays
  focusable, and the reason is its accessible name.
- That reason also lied on a built-in list, where the block has nothing to do
  with sorting or filtering. Third branch, own string.
- The open player followed a position in a derived list, so a refetch or a view
  change could slide a different video under it or unmount it mid-playback. It
  follows the video id, like PlayerModal's own queue already does.
- A failed reorder could not resync: the id set is unchanged by a reorder, so
  the arriving detail was judged "same list" and the rejected order stayed on
  screen as the base for the next drag.
- The same guard is now keyed by playlist. Two lists holding the same videos
  looked identical to it, so the second rendered in the first's order and
  inherited its undo stack — where Undo would write it back to the wrong list.
- A one-item list filtered to nothing had no Reset view: the whole control strip
  was gated on the item count while the funnels rendered regardless.
- Both delete outcomes now read as actions ("Delete here only" / "Delete here
  and on YouTube"); "Here only" scanned as the safe choice while also deleting.
- Keyboard dragging shipped with dnd-kit's hardcoded English screen-reader
  instructions and announcements. Localized, with live positions.
This commit is contained in:
2026-07-20 23:45:31 +02:00
parent 83e673718f
commit efd46a01c8
4 changed files with 131 additions and 47 deletions
+9 -3
View File
@@ -42,8 +42,7 @@
"pushDone": "“{{name}}” synced to YouTube ✓",
"pushPartial": "Synced, but {{count}} item(s) were skipped.",
"pushFailed": "Couldn't sync to YouTube.",
"deleteOnYoutubeConfirm": "Delete on YouTube",
"deleteHereOnly": "Here only",
"deleteHereOnly": "Delete here only",
"deleteYtFailed": "Couldn't delete on YouTube; removed here only.",
"sortLabel": "Sort",
"dirAsc": "Ascending",
@@ -73,5 +72,12 @@
"reorderFailed": "Couldn't save the new order.",
"renameFailed": "Couldn't rename the playlist.",
"deleteFailed": "Couldn't delete the playlist.",
"confirmDeleteLinked": "Delete the playlist “{{name}}”? It is synced with YouTube — choose whether to delete it there as well. This can't be undone."
"confirmDeleteLinked": "Delete the playlist “{{name}}”? It is synced with YouTube — choose whether to delete it there as well. This can't be undone.",
"dragBlockedBuiltin": "This list's order is fixed — it can't be reordered by hand.",
"deleteBoth": "Delete here and on YouTube",
"dndInstructions": "Press space to pick up a video, the arrow keys to move it, space again to drop it, or escape to cancel.",
"dndPickedUp": "Picked up “{{title}}”, position {{pos}} of {{total}}.",
"dndMovedOver": "“{{title}}” moved to position {{pos}} of {{total}}.",
"dndDropped": "“{{title}}” dropped at position {{pos}} of {{total}}.",
"dndCancelled": "Move cancelled; “{{title}}” is back at position {{pos}}."
}
+9 -3
View File
@@ -42,8 +42,7 @@
"pushDone": "„{{name}}” szinkronizálva a YouTube-ra ✓",
"pushPartial": "Szinkronizálva, de {{count}} elem kimaradt.",
"pushFailed": "Nem sikerült a YouTube-ra szinkronizálás.",
"deleteOnYoutubeConfirm": "Törlés a YouTube-on",
"deleteHereOnly": "Csak itt",
"deleteHereOnly": "Törlés csak itt",
"deleteYtFailed": "Nem sikerült törölni a YouTube-on; csak itt lett eltávolítva.",
"sortLabel": "Rendezés",
"dirAsc": "Növekvő",
@@ -73,5 +72,12 @@
"reorderFailed": "Nem sikerült elmenteni az új sorrendet.",
"renameFailed": "Nem sikerült átnevezni a listát.",
"deleteFailed": "Nem sikerült törölni a listát.",
"confirmDeleteLinked": "Törlöd a(z) „{{name}}” listát? A YouTube-bal szinkronban van — válaszd ki, hogy ott is törlődjön-e. Nem vonható vissza."
"confirmDeleteLinked": "Törlöd a(z) „{{name}}” listát? A YouTube-bal szinkronban van — válaszd ki, hogy ott is törlődjön-e. Nem vonható vissza.",
"dragBlockedBuiltin": "Ennek a listának kötött a sorrendje — kézzel nem rendezhető át.",
"deleteBoth": "Törlés itt és a YouTube-on",
"dndInstructions": "Szóközzel felveszed a videót, a nyilakkal mozgatod, újabb szóközzel leteszed, Escape-pel megszakítod.",
"dndPickedUp": "„{{title}}” felvéve, {{pos}}. a(z) {{total}} közül.",
"dndMovedOver": "„{{title}}” a(z) {{pos}}. helyre került a(z) {{total}} közül.",
"dndDropped": "„{{title}}” letéve a(z) {{pos}}. helyre a(z) {{total}} közül.",
"dndCancelled": "Mozgatás megszakítva; „{{title}}” visszakerült a(z) {{pos}}. helyre."
}