가상매매 화면 멀티 레이아웃 수정

This commit is contained in:
Macbook
2026-05-30 04:03:51 +09:00
parent 961609242c
commit 33c2d4b337
12 changed files with 476 additions and 217 deletions
@@ -0,0 +1,17 @@
/**
* 가상매매 — 그리드 n×n 배치 선택
*/
import GridLayoutPicker from '../common/GridLayoutPicker';
import type { TradeNotificationGridPresetId } from '../../utils/tradeNotificationGridPresets';
interface Props {
value: TradeNotificationGridPresetId;
onChange: (id: TradeNotificationGridPresetId) => void;
disabled?: boolean;
}
const VirtualGridLayoutPicker: React.FC<Props> = props => (
<GridLayoutPicker variant="vtd" popoverAlign="left" {...props} />
);
export default VirtualGridLayoutPicker;
@@ -2,6 +2,8 @@ import React from 'react';
import type { StrategyDto } from '../../utils/backendApi';
import type { VirtualSessionConfig, VirtualCardViewMode } from '../../utils/virtualTradingStorage';
import type { VirtualCardDisplayMode } from './VirtualTargetCard';
import VirtualGridLayoutPicker from './VirtualGridLayoutPicker';
import type { TradeNotificationGridPresetId } from '../../utils/tradeNotificationGridPresets';
interface SessionProps {
session: Pick<VirtualSessionConfig, 'globalStrategyId' | 'executionType' | 'positionMode' | 'running'>;
@@ -23,6 +25,9 @@ interface ViewProps {
globalDisplayMode?: VirtualCardDisplayMode;
onGlobalDisplayModeChange?: (mode: VirtualCardDisplayMode) => void;
showSignalChartToggle?: boolean;
gridPreset?: TradeNotificationGridPresetId;
onGridPresetChange?: (preset: TradeNotificationGridPresetId) => void;
showGridLayoutPicker?: boolean;
}
export const VirtualSessionHeaderControls: React.FC<SessionProps> = ({
@@ -156,8 +161,21 @@ export const VirtualViewHeaderControls: React.FC<ViewProps> = ({
globalDisplayMode = 'signal',
onGlobalDisplayModeChange,
showSignalChartToggle = true,
gridPreset = '2x2',
onGridPresetChange,
showGridLayoutPicker = true,
}) => (
<div className="vtd-header-view">
{showGridLayoutPicker && onGridPresetChange && (
<>
<VirtualGridLayoutPicker
value={gridPreset}
onChange={onGridPresetChange}
disabled={!showSignalChartToggle}
/>
<span className="vtd-grid-head-divider" aria-hidden="true" />
</>
)}
{showSignalChartToggle && onGlobalDisplayModeChange && (
<>
<div className="vtd-grid-head-group" role="group" aria-label="전체 종목 신호·차트">
@@ -95,7 +95,7 @@ const VirtualTargetCardChart: React.FC<Props> = ({
mgr.updateBar(pending);
const wrap = canvasWrapRef.current;
if (wrap && wrap.clientHeight > 0) {
mgr.resetPaneHeights(wrap.clientHeight);
mgr.applyCandleOnlyLayout(true, wrap.clientHeight);
}
}, []);
@@ -145,7 +145,7 @@ const VirtualTargetCardChart: React.FC<Props> = ({
const wrap = canvasWrapRef.current;
const mgr = managerRef.current;
if (!wrap || wrap.clientHeight <= 0 || !mgr?.hasMainSeries()) return;
mgr.resetPaneHeights(wrap.clientHeight);
mgr.applyCandleOnlyLayout(true, wrap.clientHeight);
}, []);
const requestChartReload = useCallback(() => {
@@ -169,7 +169,7 @@ const VirtualTargetCardChart: React.FC<Props> = ({
const h = canvasWrapRef.current.clientHeight;
if (h <= 0) return;
if (managerRef.current?.hasMainSeries()) {
managerRef.current.resetPaneHeights(h);
managerRef.current.applyCandleOnlyLayout(true, h);
} else if (!chartReloadTriggeredRef.current && delay >= 800 && barsReady) {
requestChartReload();
}
@@ -258,6 +258,9 @@ const VirtualTargetCardChart: React.FC<Props> = ({
magnifierEnabled={false}
volumeVisible={false}
showHoverToolbar={false}
showPaneLegend={false}
showCandlePaneControls={false}
defaultCandleOnly
seriesPriceLabelsEnabled={chartSeriesPriceLabels}
paneSeparatorOptions={chartPaneSeparator}
/>
@@ -13,6 +13,10 @@ import type { VirtualLiveStatus } from '../../hooks/useVirtualTargetLiveStatus';
import type { VirtualIndicatorSnapshot } from '../../hooks/useVirtualIndicatorSnapshots';
import type { TickerData } from '../../hooks/useMarketTicker';
import { resolveVirtualTargetStrategyId } from '../../utils/virtualTargetStrategy';
import {
getTradeNotificationGridPreset,
type TradeNotificationGridPresetId,
} from '../../utils/tradeNotificationGridPresets';
interface Props {
targets: VirtualTargetItem[];
@@ -34,6 +38,7 @@ interface Props {
viewMode: VirtualCardViewMode;
globalDisplayMode: VirtualCardDisplayMode;
onFocusMarketChange?: (market: string | null) => void;
gridPreset: TradeNotificationGridPresetId;
}
const VirtualTargetGrid: React.FC<Props> = ({
@@ -50,7 +55,9 @@ const VirtualTargetGrid: React.FC<Props> = ({
viewMode,
globalDisplayMode,
onFocusMarketChange,
gridPreset,
}) => {
const gridCols = getTradeNotificationGridPreset(gridPreset).cols;
const [cardDisplayOverrides, setCardDisplayOverrides] = useState<Record<string, VirtualCardDisplayMode>>({});
const [focusMarket, setFocusMarket] = useState<string | null>(null);
@@ -132,7 +139,15 @@ const VirtualTargetGrid: React.FC<Props> = ({
ticker={tickers?.get(focusTarget.market)}
/>
) : (
<div className={`vtd-grid vtd-grid--${viewMode}`}>
<div
className={[
'vtd-grid',
'vtd-grid--layout-preset',
`vtd-grid--${viewMode}`,
`vtd-grid--cols-${gridCols}`,
].join(' ')}
style={{ ['--vtd-grid-cols' as string]: gridCols }}
>
{targets.map(t => {
const strat = strategies.find(s => s.id === resolveVirtualTargetStrategyId(t, session.globalStrategyId));
return (