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:
@@ -0,0 +1,33 @@
|
||||
// The channel manager's layout vocabulary (E4 S3). Named `ChannelLayout` — NOT `ChannelView` — on
|
||||
// purpose: the manager already has a `ChannelsView` (the subscribed/discovery/blocked TAB), and a
|
||||
// one-letter-apart type would be a footgun. This is the table-vs-card-vs-row density switch, the
|
||||
// sibling of the feed's `FeedView`; it rides the same generic `ViewSwitcher`.
|
||||
export type ChannelLayout = "table" | "cards" | "rows";
|
||||
|
||||
export const CHANNEL_LAYOUTS: readonly ChannelLayout[] = ["table", "cards", "rows"] as const;
|
||||
|
||||
const CHANNEL_LAYOUT_DEFAULT: ChannelLayout = "table";
|
||||
|
||||
/** The card/row layouts' grid spec, consumed by VirtualGrid (S3.3). `table` has no entry — it keeps
|
||||
* the numbered-pager DataTable, not the virtualized grid. Tuned by measuring the real layouts. */
|
||||
export interface ChannelLayoutSpec {
|
||||
/** Narrowest grid column in px, or null for ONE full-width column (the row list). */
|
||||
minCol: number | null;
|
||||
/** Single-column reading-width cap in px (null = fill). */
|
||||
maxCol: number | null;
|
||||
/** First-paint row-height estimate; real heights are measured per-row after. */
|
||||
rowEst: number;
|
||||
}
|
||||
|
||||
export const CHANNEL_LAYOUT_SPEC: Record<Exclude<ChannelLayout, "table">, ChannelLayoutSpec> = {
|
||||
cards: { minCol: 300, maxCol: null, rowEst: 210 },
|
||||
rows: { minCol: null, maxCol: 1100, rowEst: 88 },
|
||||
};
|
||||
|
||||
/** Coerce a stored value to a layout; anything unknown (corrupt, a rolled-back future layout) falls
|
||||
* back to the default rather than rendering nothing. */
|
||||
export function parseChannelLayout(raw: unknown): ChannelLayout {
|
||||
return (CHANNEL_LAYOUTS as readonly string[]).includes(raw as string)
|
||||
? (raw as ChannelLayout)
|
||||
: CHANNEL_LAYOUT_DEFAULT;
|
||||
}
|
||||
@@ -24,6 +24,8 @@ export const LS = {
|
||||
feedView: "siftlode.feedView",
|
||||
channelFilter: "siftlode.channelFilter",
|
||||
channelsView: "siftlode.channelsView",
|
||||
// The channel manager's layout (table / cards / rows — see lib/channelLayout.ts), per-account.
|
||||
channelLayout: "siftlode.channelLayout",
|
||||
channelsTable: "siftlode.channelsTable",
|
||||
channelDiscoveryTable: "siftlode.channelDiscoveryTable",
|
||||
settingsTab: "siftlode.settingsTab",
|
||||
|
||||
Reference in New Issue
Block a user