feat(managers): paginate the card layout + its top scroll-fade
UAT round 3 feedback on the card layout: - Add a pager + "Cards per page" to the card view (it infinitely-scrolled before). Extracted the pager cluster out of DataTable into a reusable Pager component (the table now renders it too — no behaviour change); the card view slices the sorted rows and drives its own per-account page size (subscribed + discovery). - Restore the top edge-fade in the card layout. The channels page registers fadeTop:false for its sticky-header table; the card layout has no sticky header, so App now re-enables the top fade when the channel layout is cards.
This commit is contained in:
@@ -15,6 +15,7 @@ import AboutCell from "./AboutCell";
|
||||
import DataTable, { type Column } from "./DataTable";
|
||||
import ChannelLayoutGrid from "./ChannelLayoutGrid";
|
||||
import ColumnSortControl from "./ColumnSortControl";
|
||||
import Pager from "./Pager";
|
||||
import { PageToolbar } from "./PageShell";
|
||||
import { useConfirm } from "./ConfirmProvider";
|
||||
import { useChannels } from "./ChannelsProvider";
|
||||
@@ -47,6 +48,9 @@ export default function ChannelDiscovery({
|
||||
setSortState(s);
|
||||
writeAccount(LS.channelDiscoverySort, s);
|
||||
};
|
||||
// Card layout pagination (its own; the table keeps its rows-per-page inside DataTable).
|
||||
const [cardSize, setCardSize] = useState(() => readAccount<number>(LS.channelDiscoveryCardSize, 25));
|
||||
const [cardPage, setCardPage] = useState(0);
|
||||
|
||||
const query = useQuery({
|
||||
queryKey: ["discovered-channels"],
|
||||
@@ -180,23 +184,47 @@ export default function ChannelDiscovery({
|
||||
},
|
||||
];
|
||||
|
||||
// Card layout paginates like the table (slice the sorted rows; the Pager reports changes).
|
||||
const sortedRows = sortRows(rows, columns, sort);
|
||||
const cardTotalPages = cardSize <= 0 ? 1 : Math.max(1, Math.ceil(sortedRows.length / cardSize));
|
||||
const cardSafePage = Math.min(cardPage, cardTotalPages - 1);
|
||||
const pagedRows =
|
||||
cardSize <= 0
|
||||
? sortedRows
|
||||
: sortedRows.slice(cardSafePage * cardSize, cardSafePage * cardSize + cardSize);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Intro + the table controls are fixed chrome; only the table rows scroll (sticky header). */}
|
||||
<PageToolbar>
|
||||
<div className="px-4 pt-3 max-w-[96rem] mx-auto flex items-start justify-between gap-4">
|
||||
<p className="text-xs text-muted leading-relaxed">{t("channels.discovery.intro")}</p>
|
||||
{/* Cards has no column headers, so a dropdown drives the sort (table uses the headers). */}
|
||||
{/* Cards has no column headers, so a dropdown drives the sort + a pager (table uses its own). */}
|
||||
{layout === "cards" && (
|
||||
<ColumnSortControl
|
||||
columns={columns}
|
||||
sort={sort}
|
||||
onChange={setSort}
|
||||
label={t("channels.sort.label")}
|
||||
defaultLabel={t("channels.sort.default")}
|
||||
ascLabel={t("channels.sort.asc")}
|
||||
descLabel={t("channels.sort.desc")}
|
||||
/>
|
||||
<div className="flex items-center gap-3 shrink-0">
|
||||
<Pager
|
||||
page={cardSafePage}
|
||||
size={cardSize}
|
||||
total={sortedRows.length}
|
||||
pageSizeOptions={[10, 25, 50, 100]}
|
||||
onPageChange={setCardPage}
|
||||
onSizeChange={(s) => {
|
||||
setCardSize(s);
|
||||
writeAccount(LS.channelDiscoveryCardSize, s);
|
||||
setCardPage(0);
|
||||
}}
|
||||
sizeLabel={t("channels.cardsPerPage")}
|
||||
/>
|
||||
<ColumnSortControl
|
||||
columns={columns}
|
||||
sort={sort}
|
||||
onChange={setSort}
|
||||
label={t("channels.sort.label")}
|
||||
defaultLabel={t("channels.sort.default")}
|
||||
ascLabel={t("channels.sort.asc")}
|
||||
descLabel={t("channels.sort.desc")}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</PageToolbar>
|
||||
@@ -218,7 +246,7 @@ export default function ChannelDiscovery({
|
||||
/>
|
||||
) : (
|
||||
<ChannelLayoutGrid
|
||||
rows={sortRows(rows, columns, sort)}
|
||||
rows={pagedRows}
|
||||
columns={columns}
|
||||
rowKey={(c) => c.id}
|
||||
aboutKey="about"
|
||||
|
||||
Reference in New Issue
Block a user