feat(playlists): act on the selected rows from the toolbar, and undo either

While rows are selected the toolbar's second row is the band: the count,
the last target as one click, Move to, Remove, Clear selection. Both write
in one request and undo back to the places; a video the target held before
stays there. Delete takes the selection when there is one. A failure puts
the rows back ticked.

A row's own move goes through the same write, so it undoes too, and the
single-row move route and service function are gone. A playlist row drops
its grip below a 24rem table: the row menu keeps the moves.
This commit is contained in:
2026-11-01 22:07:09 +01:00
parent 3b85881af4
commit efbbb23525
24 changed files with 1114 additions and 236 deletions
+10 -1
View File
@@ -51,6 +51,9 @@ export interface Column<T> {
// one beside a panel: a secondary column that gives its room back to the name (the owner,
// 2026-09-27: at 1024 the channel name had 60 px while About took as much). Same `@container` rule.
tabletHidden?: boolean;
// …and one it leaves out while it is narrower than 24rem, a phone beside the nav rail: there the
// title kept 44 px. Only for a column whose job has another way (the grip: the row menu's moves).
phoneHidden?: boolean;
}
// The classes that hide a column below its width (`narrowHidden` / `tabletHidden`), for its cells and,
@@ -71,14 +74,20 @@ const HIDE_BELOW = {
col: " hidden @5xl:table-column",
cue: " @5xl:hidden",
},
phone: {
cell: " hidden @sm:table-cell",
col: " hidden @sm:table-column",
cue: " @sm:hidden",
},
} as const;
export function columnHideClass(
col: { narrowHidden?: boolean; tabletHidden?: boolean },
col: { narrowHidden?: boolean; tabletHidden?: boolean; phoneHidden?: boolean },
part: "cell" | "col" | "cue" = "cell",
): string {
if (col.narrowHidden) return HIDE_BELOW.narrow[part];
if (col.tabletHidden) return HIDE_BELOW.tablet[part];
if (col.phoneHidden) return HIDE_BELOW.phone[part];
return "";
}