fix(playlists): the selection band keeps to one row on a tablet, and a tick moves no row

Below xl the band's buttons are glyphs named in their tooltips, and the row it
replaces stays in the same grid cell, invisible, so the first tick leaves the
list where the second tap expects it. The test's row menu asked for the pins
unmocked, and the offline toast could land before the check: mocked.
This commit is contained in:
2026-11-01 22:44:32 +01:00
parent efbbb23525
commit bf54a3ce5f
6 changed files with 144 additions and 44 deletions
+38 -26
View File
@@ -98,6 +98,7 @@ import { useCopyItems } from "../../components/ui/copyItems";
import RemoteImage from "../../components/ui/RemoteImage";
import PlaylistsHeader from "./PlaylistsHeader";
import { SelectionBand } from "./SelectionBand";
import clsx from "clsx";
// The playlist detail is a HYBRID table: real sortable/filterable column headers over a
// body that is still a drag-reorderable @dnd-kit list.
@@ -1239,32 +1240,43 @@ function PlaylistDetail() {
</div>
</div>
{bandUp ? (
<SelectionBand
ref={bandRef}
count={selection.shownSelected.length}
hidden={selection.hiddenCount}
recentName={recentMoveTarget ? plName(recentMoveTarget) : null}
onMoveRecent={() => recentMoveTarget && moveSelected(recentMoveTarget)}
moveMenuProps={moveMenu.buttonProps("selection")}
moveMenuOpen={moveMenu.open}
onRemove={removeSelected}
onClear={() => {
leaveBand();
selection.clear();
}}
onClearView={viewActive ? clearView : undefined}
trailing={
<UndoToolbar
canUndo={order.canUndo}
canRedo={order.canRedo}
onUndo={order.undo}
onRedo={order.redo}
{/* One cell: the row a selection replaces keeps its height, invisible, so the first
tick moves no row under the second tap, however the two wrap. */}
<div className="grid">
{bandUp && (
<div className="[grid-area:1/1]">
<SelectionBand
ref={bandRef}
count={selection.shownSelected.length}
hidden={selection.hiddenCount}
recentName={recentMoveTarget ? plName(recentMoveTarget) : null}
onMoveRecent={() => recentMoveTarget && moveSelected(recentMoveTarget)}
moveMenuProps={moveMenu.buttonProps("selection")}
moveMenuOpen={moveMenu.open}
onRemove={removeSelected}
onClear={() => {
leaveBand();
selection.clear();
}}
onClearView={viewActive ? clearView : undefined}
trailing={
<UndoToolbar
canUndo={order.canUndo}
canRedo={order.canRedo}
onUndo={order.undo}
onRedo={order.redo}
/>
}
/>
}
/>
) : (
<div className="flex items-center gap-2 mt-1 flex-wrap">
</div>
)}
<div
aria-hidden={bandUp || undefined}
className={clsx(
"flex items-center gap-2 mt-1 flex-wrap [grid-area:1/1]",
bandUp && "invisible",
)}
>
<span className="text-xs text-muted">
{t("playlists.itemCount", { count: items.length })}
{totalSeconds > 0 && ` · ${formatRuntime(totalSeconds, lang)}`}
@@ -1323,7 +1335,7 @@ function PlaylistDetail() {
</>
)}
</div>
)}
</div>
</div>
</div>
</div>