125 lines
3.9 KiB
TypeScript
125 lines
3.9 KiB
TypeScript
/** 매매 알림 팝업 표시 위치 */
|
||
export type TradeAlertPopupPosition = 'right' | 'left' | 'bottom';
|
||
|
||
/** 매매 알림 팝업 배치 방식 */
|
||
export type TradeAlertPopupLayout = 'stack' | 'grid' | 'strip' | 'single';
|
||
|
||
export const TRADE_ALERT_POPUP_POSITIONS: { id: TradeAlertPopupPosition; label: string; desc: string }[] = [
|
||
{ id: 'right', label: '화면 우측', desc: '우측 상단부터 아래로 쌓입니다 (기본)' },
|
||
{ id: 'left', label: '화면 좌측', desc: '좌측 상단부터 아래로 쌓입니다' },
|
||
{ id: 'bottom', label: '화면 하단', desc: '화면 하단 중앙에 표시됩니다' },
|
||
];
|
||
|
||
export const TRADE_ALERT_POPUP_LAYOUTS: { id: TradeAlertPopupLayout; label: string; desc: string }[] = [
|
||
{ id: 'stack', label: '세로 스택', desc: '알림을 위·아래로 순서대로 쌓아 표시' },
|
||
{ id: 'grid', label: '그리드 (N×N)', desc: '알림을 격자 형태로 배치' },
|
||
{ id: 'strip', label: '가로 나열', desc: '알림을 가로로 나열 (스크롤)' },
|
||
{ id: 'single', label: '최신 1건', desc: '가장 최근 알림 1건만 표시' },
|
||
];
|
||
|
||
export const TRADE_ALERT_GRID_COL_OPTIONS = [2, 3, 4] as const;
|
||
|
||
export function normalizeTradeAlertPopupPosition(raw?: string | null): TradeAlertPopupPosition {
|
||
if (raw === 'left' || raw === 'bottom') return raw;
|
||
return 'right';
|
||
}
|
||
|
||
export function normalizeTradeAlertPopupLayout(raw?: string | null): TradeAlertPopupLayout {
|
||
if (raw === 'grid' || raw === 'strip' || raw === 'single') return raw;
|
||
return 'stack';
|
||
}
|
||
|
||
export function normalizeTradeAlertGridCols(raw?: number | null): number {
|
||
const n = raw ?? 2;
|
||
return Math.min(4, Math.max(2, Math.round(n)));
|
||
}
|
||
|
||
/** CSS 클래스 조합 */
|
||
export function tradeAlertPopupClassNames(
|
||
position: TradeAlertPopupPosition,
|
||
layout: TradeAlertPopupLayout,
|
||
): { stack: string; cards: string } {
|
||
return {
|
||
stack: `tsn-stack tsn-stack--${position} tsn-layout--${layout}`,
|
||
cards: `tsn-cards tsn-cards--${layout}`,
|
||
};
|
||
}
|
||
|
||
const POSITION_SHORT: Record<TradeAlertPopupPosition, string> = {
|
||
right: '우측',
|
||
left: '좌측',
|
||
bottom: '하단',
|
||
};
|
||
|
||
const LAYOUT_SHORT: Record<TradeAlertPopupLayout, string> = {
|
||
stack: '스택',
|
||
grid: '그리드',
|
||
strip: '가로',
|
||
single: '1건',
|
||
};
|
||
|
||
export function tradeAlertPopupModeKey(
|
||
position: TradeAlertPopupPosition,
|
||
layout: TradeAlertPopupLayout,
|
||
): string {
|
||
return `${position}:${layout}`;
|
||
}
|
||
|
||
export function parseTradeAlertPopupModeKey(key: string): {
|
||
position: TradeAlertPopupPosition;
|
||
layout: TradeAlertPopupLayout;
|
||
} {
|
||
const [pos, lay] = key.split(':');
|
||
return {
|
||
position: normalizeTradeAlertPopupPosition(pos),
|
||
layout: normalizeTradeAlertPopupLayout(lay),
|
||
};
|
||
}
|
||
|
||
export function formatTradeAlertPopupMode(
|
||
position: TradeAlertPopupPosition,
|
||
layout: TradeAlertPopupLayout,
|
||
): string {
|
||
return `${POSITION_SHORT[position]} · ${LAYOUT_SHORT[layout]}`;
|
||
}
|
||
|
||
/** 메뉴바 드롭다운용 — 위치별 배치 옵션 */
|
||
export function buildTradeAlertPopupModeOptions(): {
|
||
position: TradeAlertPopupPosition;
|
||
layout: TradeAlertPopupLayout;
|
||
key: string;
|
||
label: string;
|
||
}[] {
|
||
const options: {
|
||
position: TradeAlertPopupPosition;
|
||
layout: TradeAlertPopupLayout;
|
||
key: string;
|
||
label: string;
|
||
}[] = [];
|
||
for (const pos of TRADE_ALERT_POPUP_POSITIONS) {
|
||
for (const lay of TRADE_ALERT_POPUP_LAYOUTS) {
|
||
options.push({
|
||
position: pos.id,
|
||
layout: lay.id,
|
||
key: tradeAlertPopupModeKey(pos.id, lay.id),
|
||
label: `${pos.label} · ${lay.label}`,
|
||
});
|
||
}
|
||
}
|
||
return options;
|
||
}
|
||
|
||
/** @deprecated useToastPageCapacity 훅 사용 */
|
||
export function getToastPageSize(
|
||
layout: TradeAlertPopupLayout,
|
||
gridCols: number,
|
||
): number {
|
||
switch (layout) {
|
||
case 'single': return 1;
|
||
case 'strip': return 4;
|
||
case 'grid': return normalizeTradeAlertGridCols(gridCols) * 4;
|
||
case 'stack':
|
||
default: return 5;
|
||
}
|
||
}
|