feat(managers): table / cards / rows layouts for the channel manager (E4 S3)

A generic ViewSwitcher (reused from the feed) drives a per-account layout
shared by the Subscriptions + Discovery tabs. `table` keeps the DataTable
(numbered pager); `cards` and `rows` render a virtualized grid over the same
client-side list via the new ChannelLayoutGrid, which composes cells straight
from each table's Column<T> render closures (cardPrimary/hideInCard/cardLabel),
so both tabs — with their different columns — get the views for free. Status
chips surface in the fixed band when the table's own controls row is gone.
This commit is contained in:
2026-07-19 21:52:16 +02:00
parent 5ea82095a1
commit 1703d4ab5e
8 changed files with 226 additions and 9 deletions
+14 -1
View File
@@ -11,8 +11,10 @@ import Tooltip from "./Tooltip";
import ChannelLink from "./ChannelLink";
import AboutCell from "./AboutCell";
import DataTable, { type Column } from "./DataTable";
import ChannelLayoutGrid from "./ChannelLayoutGrid";
import { PageToolbar } from "./PageShell";
import { useConfirm } from "./ConfirmProvider";
import { useChannels } from "./ChannelsProvider";
// The Channel manager's "Discovery" tab: channels that turn up in the user's playlists but
// that they don't subscribe to. Subscribing here only creates the subscription + enriches
@@ -32,6 +34,8 @@ export default function ChannelDiscovery({
const { t } = useTranslation();
const qc = useQueryClient();
const confirm = useConfirm();
// The table/cards/rows density is shared with the Subscriptions tab (ChannelsProvider).
const { layout } = useChannels();
const query = useQuery({
queryKey: ["discovered-channels"],
@@ -172,7 +176,7 @@ export default function ChannelDiscovery({
<div className="px-4 pb-4 max-w-[96rem] mx-auto">
{query.isLoading ? (
<div className="text-muted py-8">{t("channels.discovery.loading")}</div>
) : (
) : layout === "table" ? (
<DataTable
rows={rows}
columns={columns}
@@ -183,6 +187,15 @@ export default function ChannelDiscovery({
controlsBandClassName="px-4 max-w-[96rem] mx-auto"
emptyText={t("channels.discovery.empty")}
/>
) : (
<ChannelLayoutGrid
rows={rows}
columns={columns}
rowKey={(c) => c.id}
layout={layout}
actionsKey="actions"
emptyText={t("channels.discovery.empty")}
/>
)}
</div>
</>