feat(design): a playlist's one action list (C1) — the row's "…", Delete + undo, the header's "…" (E28 S3e2)

- Playlist rows: the X column became the row's "…" (play, pin, copy title/link, move, order,
  remove). Remove runs at once, with no confirm; its toast's Undo puts the row back at its index.
  The Delete key removes a keyboard-walked row, and focus moves on to the next.
- POST /api/playlists/{id}/items takes an optional `position`, so an undo is one request that
  renumbers the list around the row.
- A new `listDelete` key scope. Only a list with `onDelete` registers it, so the help sheet does not
  offer Delete where nothing handles it.
- A playlist has one list, `usePlaylistActions.items`: rename, pin, YouTube open/push/revert,
  delete. The rail row's "…" and the page header's "…" both open it. Push and revert moved into
  the hook; the header keeps Play all.
- Phone-width playlist table: "#" and Channel are hidden below sm (`Column.phoneHidden`). Their
  fixed widths had left the title no width.
This commit is contained in:
2026-09-26 04:05:39 +02:00
parent aaf1843b09
commit 7455fff401
24 changed files with 1061 additions and 425 deletions
+1
View File
@@ -35,6 +35,7 @@
"listStep": "Next / previous item",
"gridMove": "Move around the list",
"open": "Open the selected item",
"listRemove": "Remove the selected item from the list",
"cap": {
"space": "Space",
"menu": "Menu"
+2 -1
View File
@@ -75,6 +75,8 @@
"moveNoTargets": "There is no other playlist to move it to yet.",
"movedToast": "“{{title}}” moved to “{{name}}” ✓",
"moveFailed": "Couldn't move the video.",
"removedToast": "“{{title}}” removed from the playlist",
"undoRemoveFailed": "Couldn't put the video back.",
"removeFailed": "Couldn't remove the video.",
"errors": {
"name_required": "Give the playlist a name.",
@@ -97,7 +99,6 @@
"builtinLocked": "The built-in {{name}} list can’t be renamed or deleted.",
"removeItem": "Remove",
"removeItemOf": "Remove “{{title}}” from the playlist",
"confirmRemove": "Remove “{{title}}” from this playlist?",
"dragHandleOf": "Reorder “{{title}}”",
"dragBlockedSort": "Reordering by hand is off while a column sort or grouping is applied.",
"dragBlockedFilter": "Reordering by hand is off while a filter is applied.",
+1
View File
@@ -35,6 +35,7 @@
"listStep": "Következő / előző elem",
"gridMove": "Mozgás a listában",
"open": "A kijelölt elem megnyitása",
"listRemove": "A kijelölt elem eltávolítása a listából",
"cap": {
"space": "Szóköz",
"menu": "Menü"
+2 -1
View File
@@ -75,6 +75,8 @@
"moveNoTargets": "Még nincs másik lejátszási lista, ahová áthelyezhetnéd.",
"movedToast": "„{{title}}” áthelyezve ide: „{{name}}” ✓",
"moveFailed": "Nem sikerült áthelyezni a videót.",
"removedToast": "„{{title}}” eltávolítva a listáról",
"undoRemoveFailed": "Nem sikerült visszatenni a videót.",
"removeFailed": "Nem sikerült eltávolítani a videót.",
"errors": {
"name_required": "Adj nevet a lejátszási listának.",
@@ -97,7 +99,6 @@
"builtinLocked": "A beépített „{{name}}” lista nem nevezhető át és nem törölhető.",
"removeItem": "Eltávolítás",
"removeItemOf": "„{{title}}” eltávolítása a listáról",
"confirmRemove": "Eltávolítod a(z) „{{title}}” videót erről a listáról?",
"dragHandleOf": "„{{title}}” átrendezése",
"dragBlockedSort": "A kézi átrendezés ki van kapcsolva, amíg oszloprendezés vagy csoportosítás van érvényben.",
"dragBlockedFilter": "A kézi átrendezés ki van kapcsolva, amíg szűrő van érvényben.",