feat(playlists): select rows with a box, Shift for a range, x and Esc
A box first in every row and one over the column for the rows shown, the selected row tinted. A filter keeps what it hides selected; another list starts over; a row that left the list drops out. Watch later has none. A box no longer counts as a typing target: a click on one left the focus there and the page's keys went dead.
This commit is contained in:
@@ -6,6 +6,7 @@ import { formatDuration } from "../../lib/format";
|
||||
import type { Column } from "../../lib/tableColumns";
|
||||
import { Pressable } from "../../components/ui/Pressable";
|
||||
import RemoteImage from "../../components/ui/RemoteImage";
|
||||
import { RowSelectBox } from "../../components/ui/RowSelectBox";
|
||||
|
||||
// Column definitions for the playlist detail table, in their own file like `channelColumns.tsx`.
|
||||
//
|
||||
@@ -145,6 +146,46 @@ export function playlistColumns({
|
||||
return cols;
|
||||
}
|
||||
|
||||
/** The box column, first in the row, for a list whose rows can be selected. A separate column from
|
||||
* `playlistColumns`, whose array the view's filter and sort read: a tick must not re-run them. */
|
||||
export function selectColumn({
|
||||
t,
|
||||
state,
|
||||
onToggleAll,
|
||||
isSelected,
|
||||
onToggle,
|
||||
}: {
|
||||
t: TFunction;
|
||||
state: "none" | "some" | "all";
|
||||
onToggleAll: () => void;
|
||||
isSelected: (id: string) => boolean;
|
||||
onToggle: (id: string, range: boolean) => void;
|
||||
}): Column<Video> {
|
||||
const allLabel = t("playlists.selectAllShown");
|
||||
return {
|
||||
key: "select",
|
||||
header: allLabel,
|
||||
headerCell: (
|
||||
<RowSelectBox
|
||||
label={allLabel}
|
||||
title={allLabel}
|
||||
checked={state === "all"}
|
||||
mixed={state === "some"}
|
||||
onToggle={onToggleAll}
|
||||
/>
|
||||
),
|
||||
width: "2.25rem",
|
||||
hideInCard: true,
|
||||
render: (v) => (
|
||||
<RowSelectBox
|
||||
label={t("playlists.selectRow", { title: v.title })}
|
||||
checked={isSelected(v.id)}
|
||||
onToggle={(shift) => onToggle(v.id, shift)}
|
||||
/>
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
// A video's length, or its live / upcoming state when it has none. `onPicture`: the dark badge on the
|
||||
// thumbnail (the narrow row), readable on any frame, like the media card's length badge.
|
||||
function lengthCell(v: Video, t: TFunction, onPicture = false): ReactNode {
|
||||
|
||||
Reference in New Issue
Block a user