Introduce the one sort control every content surface will share: - columnSort.ts gains the SortOption vocabulary + pure pickSort/healSort/ hydrateSort helpers (direction lives in SortState, never in the key). - SortControl.tsx: the generic dropdown + asc/desc toggle, with an optional "no sort" choice (tables) and a trailing adornment slot (the feed's reshuffle). - ColumnSortControl is now a thin wrapper over SortControl (API unchanged, so Channels + ChannelDiscovery are untouched); optionsFromColumns moved to lib/sortOptions.ts to keep the component file fast-refresh clean. - useSortState.ts: the per-account persist/hydrate/heal plumbing the channel manager and discovery each hand-rolled, ready to replace both. Pure logic is fully unit-tested (columnSort.test.ts 10 -> 23). Gate green: tsc/eslint/prettier clean, vitest 93 pass. Feed/Plex/channels migration follows.
41 lines
1.2 KiB
TypeScript
41 lines
1.2 KiB
TypeScript
import { type Column } from "./DataTable";
|
|
import { type SortState } from "../lib/columnSort";
|
|
import { optionsFromColumns } from "../lib/sortOptions";
|
|
import SortControl from "./SortControl";
|
|
|
|
// The headerless sort control for views without clickable column headers (the channel manager's and
|
|
// discovery's card layouts). Now a thin adapter over the generic `SortControl`, feeding it the
|
|
// column-derived options and a "no sort" default — kept as its own component so the existing call
|
|
// sites stay untouched and table/cards keep sharing one `SortState`.
|
|
export default function ColumnSortControl<T>({
|
|
columns,
|
|
sort,
|
|
onChange,
|
|
label,
|
|
defaultLabel,
|
|
ascLabel,
|
|
descLabel,
|
|
}: {
|
|
columns: Column<T>[];
|
|
sort: SortState;
|
|
onChange: (next: SortState) => void;
|
|
/** Accessible name for the dropdown (e.g. "Sort"). */
|
|
label: string;
|
|
/** The "no sort / original order" option's text. */
|
|
defaultLabel: string;
|
|
ascLabel: string;
|
|
descLabel: string;
|
|
}) {
|
|
return (
|
|
<SortControl
|
|
options={optionsFromColumns(columns)}
|
|
sort={sort}
|
|
onChange={onChange}
|
|
label={label}
|
|
defaultLabel={defaultLabel}
|
|
ascLabel={ascLabel}
|
|
descLabel={descLabel}
|
|
/>
|
|
);
|
|
}
|