feat(managers): richer channel cards + drop the rows layout, cap the channel column
UAT round 1 feedback: - Retire the `rows` layout — it barely differed from the table; keep Table + Cards. - The card now shows the About cell (+ its hover overlay) and the priority stepper in every layout, not just the table: ChannelLayoutGrid gains named slots (lead / about / actions) and stops hiding the `hideInCard` columns, since the roomy desktop card has space the cramped mobile fallback did not. - Fix the table losing its centering with "Rows per page: All": a long-titled channel stretched the uncapped Channel column (~289→429px) and overflowed the centered table. Cap it with a max-w element inside the cell (table-layout:auto ignores a cell max-width), the same trick AboutCell already uses. Gaps now 163/162.
This commit is contained in:
@@ -1,33 +1,30 @@
|
||||
// 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";
|
||||
// one-letter-apart type would be a footgun. This is the table-vs-card density switch, riding the
|
||||
// same generic `ViewSwitcher` as the feed. Two layouts: the DataTable, and a virtualized card grid.
|
||||
// (A `rows` variant existed briefly but was retired — it barely differed from the table.)
|
||||
export type ChannelLayout = "table" | "cards";
|
||||
|
||||
export const CHANNEL_LAYOUTS: readonly ChannelLayout[] = ["table", "cards", "rows"] as const;
|
||||
export const CHANNEL_LAYOUTS: readonly ChannelLayout[] = ["table", "cards"] 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. */
|
||||
/** The `cards` layout's grid spec, consumed by VirtualGrid. `table` has no entry — it keeps the
|
||||
* numbered-pager DataTable, not the virtualized grid. */
|
||||
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. */
|
||||
/** Narrowest grid column in px. */
|
||||
minCol: number;
|
||||
/** First-paint row-height estimate; real heights are measured per-row after. Measured in the
|
||||
* browser (channel heading + About line + meta + tags + actions), not guessed. */
|
||||
rowEst: number;
|
||||
}
|
||||
|
||||
// rowEst measured in the browser (cards ~176 at 3 columns, the one-line row ~62) — not guessed; a
|
||||
// bad estimate makes the scrollbar jump as you first scroll in.
|
||||
export const CHANNEL_LAYOUT_SPEC: Record<Exclude<ChannelLayout, "table">, ChannelLayoutSpec> = {
|
||||
cards: { minCol: 300, maxCol: null, rowEst: 176 },
|
||||
rows: { minCol: null, maxCol: 1100, rowEst: 62 },
|
||||
cards: { minCol: 320, rowEst: 232 },
|
||||
};
|
||||
|
||||
/** Coerce a stored value to a layout; anything unknown (corrupt, a rolled-back future layout) falls
|
||||
* back to the default rather than rendering nothing. */
|
||||
/** Coerce a stored value to a layout; anything unknown (corrupt, a rolled-back future layout, or the
|
||||
* retired "rows") 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)
|
||||
|
||||
Reference in New Issue
Block a user