Files
goldenChart/frontend/src/hooks/useToastPageCapacity.ts
T
2026-05-23 15:11:48 +09:00

119 lines
3.0 KiB
TypeScript

import { useEffect, useState } from 'react';
import {
type TradeAlertPopupLayout,
type TradeAlertPopupPosition,
normalizeTradeAlertGridCols,
} from '../utils/tradeAlertPopupLayout';
export interface ToastPageCapacity {
pageSize: number;
effectiveCols: number;
effectiveRows: number;
}
const MENUBAR_H = 52;
const EDGE_PAD = 32;
const TOOLBAR_RESERVE = 88;
const CARD_GAP = 10;
/** 우측 ‹ › 슬라이드 버튼 + 간격 */
const NAV_BTN_RESERVE = 80;
const CARD = {
full: { w: 380, h: 158 },
compact:{ w: 200, h: 86 },
strip: { w: 280, h: 86 },
} as const;
function clamp(n: number, min: number, max: number): number {
return Math.min(max, Math.max(min, n));
}
export function computeToastPageCapacity(
layout: TradeAlertPopupLayout,
position: TradeAlertPopupPosition,
gridCols: number,
viewportW: number,
viewportH: number,
): ToastPageCapacity {
const availW = position === 'bottom'
? viewportW - EDGE_PAD - NAV_BTN_RESERVE
: Math.min(420, viewportW - EDGE_PAD - NAV_BTN_RESERVE);
const availH = position === 'bottom'
? Math.min(viewportH * 0.52, 440) - TOOLBAR_RESERVE
: viewportH - MENUBAR_H - EDGE_PAD - TOOLBAR_RESERVE;
if (layout === 'single') {
return { pageSize: 1, effectiveCols: 1, effectiveRows: 1 };
}
if (layout === 'strip') {
const cols = clamp(
Math.floor((availW + CARD_GAP) / (CARD.strip.w + CARD_GAP)),
1,
8,
);
return { pageSize: cols, effectiveCols: cols, effectiveRows: 1 };
}
if (layout === 'grid') {
const configured = normalizeTradeAlertGridCols(gridCols);
const maxCols = clamp(
Math.floor((availW + CARD_GAP) / (CARD.compact.w + CARD_GAP)),
1,
4,
);
const cols = Math.min(configured, maxCols);
const rows = clamp(
Math.floor((availH + CARD_GAP) / (CARD.compact.h + CARD_GAP)),
1,
6,
);
return {
pageSize: clamp(cols * rows, 1, 24),
effectiveCols: cols,
effectiveRows: rows,
};
}
// stack
const rows = clamp(
Math.floor((availH + CARD_GAP) / (CARD.full.h + CARD_GAP)),
1,
8,
);
return { pageSize: rows, effectiveCols: 1, effectiveRows: rows };
}
export function useToastPageCapacity(
layout: TradeAlertPopupLayout,
position: TradeAlertPopupPosition,
gridCols: number,
): ToastPageCapacity {
const [capacity, setCapacity] = useState<ToastPageCapacity>(() =>
computeToastPageCapacity(
layout,
position,
gridCols,
typeof window !== 'undefined' ? window.innerWidth : 1280,
typeof window !== 'undefined' ? window.innerHeight : 800,
),
);
useEffect(() => {
const update = () => {
setCapacity(computeToastPageCapacity(
layout,
position,
gridCols,
window.innerWidth,
window.innerHeight,
));
};
update();
window.addEventListener('resize', update);
return () => window.removeEventListener('resize', update);
}, [layout, position, gridCols]);
return capacity;
}