Files
siftlode/frontend/src/components/ui/gridColumns.ts
T
peter 4aaaaa7860 chore(comments): drop epic, sprint and review-round ids from the code
The code cited its plan instead of saying why: `E28 review J4`, `(R6 S3b)`, `S1 justified…`,
`deep-review round 5`. That plan lives in the private ops repo, so for every reader of this one the
citation was noise, and a sentence whose subject was the plan step ("round 2 showed…") hid its
lesson behind an id. Each one is gone and the "why" kept: a bare citation is deleted, a sentence
carrying a lesson is reworded around it ("a later attempt showed…").

Measured (`scripts/audit_metrics.py`, product code): 652 lines in 270 files carried an epic code by
the definition the next commit holds (507 / 241 by the old, two-digit-only one) -> 0. Across all
code, tests, scripts and configs: ~1100 epic-code lines plus ~320 sprint/round ids.

Behaviour unchanged, checked mechanically: every changed .py file has the same AST once docstrings
are blanked; css/sh/toml/yml/json files are identical once comments are stripped; the only
non-comment changes in TS/JS are test titles, one description string in a contract table, and five
ESLint messages, whose text is all the gates snapshot diff holds. Not touched: Markdown (docs and
the changelog keep their history), Alembic migrations, TV episode notation (`S2 · E5`), DESIGN.md
ids (`C1`, `B4`, `S3h`), tracker ids (`SEC-16`, `DX-17`).

One stale claim fixed on the way: test_hls_reaper's docstring said the player checkpoints "every
10 s whether or not it is playing", which plex/stream.py calls wrong; it now says what the code does.
2026-10-05 00:19:39 +02:00

34 lines
1.8 KiB
TypeScript

// VirtualGrid's column-count policy, extracted as a pure function so the viewport contract's UPPER
// end is unit-testable without a layout engine (the lower end, the 768-wide tablet floor, needs no policy —
// the grid simply drops to the columns that fit).
//
// An auto-fill grid answers "more room" with more columns, never bigger ones, so it always settles
// just above its minimum column width no matter how wide the screen is. Measured at 3440px,
// the feed laid out 11 columns of 264px — a diluted feed is as bad a failure of the viewport contract
// as a broken one, so `maxCols` stops the multiplication and lets the leftover width flow into the
// items instead. The cap can only bind ABOVE the width at which that many columns already fit, so the
// 1024px floor and everything near it is unchanged. How far up that reaches is per view: the feed's
// small cards (`feedView.cardsSmall`, 11) are already capped at 2560 with the filter rail collapsed —
// 12 would fit there — while the regular cards stay uncapped up to 2560.
/** The grid's gutter in px; the column maths has to net it out on both sides of the division. */
export const GRID_GAP = 16;
/** Columns that fit `width` (never more than `maxCols`), or 1 for the single-column layout
* (`minCol == null`). */
export function columnsFor(
minCol: number | null,
width: number,
maxCols: number | null = null,
): number {
if (minCol == null) return 1;
const fit = Math.max(1, Math.floor((width + GRID_GAP) / (minCol + GRID_GAP)));
return maxCols == null ? fit : Math.min(fit, maxCols);
}
/** The px width one item gets once `columnsFor` has chosen the count — i.e. where the width saved by
* the cap actually goes. */
export function itemWidthFor(width: number, cols: number): number {
return Math.floor((width - GRID_GAP * (cols - 1)) / cols);
}