feat(B06): 54-34 횡단 카드 한 줄 수 자동 · 카드 폭 400~800

보기 칸 높이에 첫 줄 + 둘째 줄 절반이 드는 가장 적은 카드 수를 고름 (카드 폭 400~800px 상수는 Section_Common 한 곳). 그림은 px 그대로. 창 크기 · 패널 높이 변화 때 다시 맞춤 (높이만 바뀌면 카드 수가 바뀔 때만 다시 그림).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgChuAcyBqUkhHMTXomQC7
This commit is contained in:
2026-10-06 14:00:38 +09:00
co-authored by Claude Sonnet 5.5
parent 265ad47aee
commit 6912246fb0
3 changed files with 100 additions and 25 deletions
@@ -0,0 +1,47 @@
/* =============================================================================
* B06_Section_UI_Section_Columns.ts
* 횡단 카드 한 줄 카드 수 고르기 — 보기 칸 높이에 첫 줄 + 둘째 줄 절반이 들어가는
* 가장 적은 카드 수. 카드 폭은 최소~최대 폭 안(그림은 축척 그대로 · 폭만 바뀜).
* ========================================================================== */
import {
CROSS_CARD_CHROME,
CROSS_GRID_GAP,
CROSS_GRID_MAX_WIDTH,
CROSS_GRID_MIN_WIDTH,
} from "./B06_Section_UI_Section_Common";
export interface CrossColumns {
columns: number;
cardWidth: number;
}
const widthFor = (columns: number, viewWidth: number): number =>
Math.min(CROSS_GRID_MAX_WIDTH, (viewWidth - (columns - 1) * CROSS_GRID_GAP) / columns);
/**
* `heightsFor(cardWidth, count)` — 그 폭일 때 앞 `count` 장의 카드 자연 높이.
* `viewHeight` 가 0 이하(숨김 · 아직 안 잰 칸)면 가장 큰 카드 쪽을 고른다.
*/
export function pickCrossColumns(
viewWidth: number,
viewHeight: number,
heightsFor: (cardWidth: number, count: number) => number[],
): CrossColumns {
const unit = CROSS_GRID_MIN_WIDTH + CROSS_GRID_GAP;
const most = Math.max(1, Math.floor((viewWidth + CROSS_GRID_GAP) / unit));
const fewest = Math.min(
most,
Math.max(1, Math.ceil((viewWidth + CROSS_GRID_GAP) / (CROSS_GRID_MAX_WIDTH + CROSS_GRID_GAP))),
);
for (let columns = fewest; columns < most; columns += 1) {
const cardWidth = widthFor(columns, viewWidth);
if (viewHeight <= 0) return { columns, cardWidth };
const heights = heightsFor(cardWidth, columns * 2);
const first = Math.max(0, ...heights.slice(0, columns)) + CROSS_CARD_CHROME;
const second = Math.max(0, ...heights.slice(columns)) + CROSS_CARD_CHROME;
const needed = heights.length > columns ? first + CROSS_GRID_GAP + second / 2 : first;
if (needed <= viewHeight) return { columns, cardWidth };
}
return { columns: most, cardWidth: widthFor(most, viewWidth) };
}