전략평가 차트, 조건 영역 사이즈조절
This commit is contained in:
@@ -82,6 +82,10 @@ const RIGHT_KEY = 'seval-right-width';
|
|||||||
const RIGHT_OPEN_KEY = 'seval-right-open';
|
const RIGHT_OPEN_KEY = 'seval-right-open';
|
||||||
const LEFT_DEFAULT = 380;
|
const LEFT_DEFAULT = 380;
|
||||||
const RIGHT_DEFAULT = 440;
|
const RIGHT_DEFAULT = 440;
|
||||||
|
const STRATEGY_PANEL_HEIGHT_KEY = 'seval-strategy-panel-height';
|
||||||
|
const STRATEGY_PANEL_MIN = 160;
|
||||||
|
const STRATEGY_PANEL_MAX = 520;
|
||||||
|
const STRATEGY_PANEL_DEFAULT = 280;
|
||||||
|
|
||||||
type LeftTab = 'strategy' | 'market' | 'settings';
|
type LeftTab = 'strategy' | 'market' | 'settings';
|
||||||
type RightTab = 'signal' | 'indicators' | 'chart' | 'ai';
|
type RightTab = 'signal' | 'indicators' | 'chart' | 'ai';
|
||||||
@@ -223,6 +227,9 @@ function StrategyEvaluationPageInner({ theme = 'dark' }: Props) {
|
|||||||
const [leftOpen, setLeftOpen] = useState(() => readStoredBool(LEFT_OPEN_KEY, true));
|
const [leftOpen, setLeftOpen] = useState(() => readStoredBool(LEFT_OPEN_KEY, true));
|
||||||
const [rightWidth, setRightWidth] = useState(() => readMinWidth(RIGHT_KEY, RIGHT_DEFAULT));
|
const [rightWidth, setRightWidth] = useState(() => readMinWidth(RIGHT_KEY, RIGHT_DEFAULT));
|
||||||
const [rightOpen, setRightOpen] = useState(() => readStoredBool(RIGHT_OPEN_KEY, true));
|
const [rightOpen, setRightOpen] = useState(() => readStoredBool(RIGHT_OPEN_KEY, true));
|
||||||
|
const [strategyPanelHeight, setStrategyPanelHeight] = useState(() =>
|
||||||
|
readStoredSize(STRATEGY_PANEL_HEIGHT_KEY, STRATEGY_PANEL_DEFAULT),
|
||||||
|
);
|
||||||
|
|
||||||
/** 종목 탭·종목검색 전용 ticker — 차트 OHLCV·scan-signals 와 분리 (upbitWsBroker ticker 채널) */
|
/** 종목 탭·종목검색 전용 ticker — 차트 OHLCV·scan-signals 와 분리 (upbitWsBroker ticker 채널) */
|
||||||
const marketTabActive = leftOpen && leftTab === 'market';
|
const marketTabActive = leftOpen && leftTab === 'market';
|
||||||
@@ -235,10 +242,20 @@ function StrategyEvaluationPageInner({ theme = 'dark' }: Props) {
|
|||||||
|
|
||||||
const leftRef = useRef(leftWidth);
|
const leftRef = useRef(leftWidth);
|
||||||
const rightRef = useRef(rightWidth);
|
const rightRef = useRef(rightWidth);
|
||||||
|
const strategyPanelHeightRef = useRef(strategyPanelHeight);
|
||||||
leftRef.current = leftWidth;
|
leftRef.current = leftWidth;
|
||||||
rightRef.current = rightWidth;
|
rightRef.current = rightWidth;
|
||||||
|
strategyPanelHeightRef.current = strategyPanelHeight;
|
||||||
|
|
||||||
const onLeftSplit = usePanelResize('vertical', setLeftWidth, () => leftRef.current, 300, 520, v => storeSize(LEFT_KEY, v));
|
const onLeftSplit = usePanelResize('vertical', setLeftWidth, () => leftRef.current, 300, 520, v => storeSize(LEFT_KEY, v));
|
||||||
|
const onStrategyPanelSplit = usePanelResize(
|
||||||
|
'horizontal',
|
||||||
|
setStrategyPanelHeight,
|
||||||
|
() => strategyPanelHeightRef.current,
|
||||||
|
STRATEGY_PANEL_MIN,
|
||||||
|
STRATEGY_PANEL_MAX,
|
||||||
|
v => storeSize(STRATEGY_PANEL_HEIGHT_KEY, v),
|
||||||
|
);
|
||||||
|
|
||||||
const toggleLeftPanel = useCallback(() => {
|
const toggleLeftPanel = useCallback(() => {
|
||||||
setLeftOpen(prev => {
|
setLeftOpen(prev => {
|
||||||
@@ -983,7 +1000,8 @@ function StrategyEvaluationPageInner({ theme = 'dark' }: Props) {
|
|||||||
|
|
||||||
<main className={`btd-main${leftOpen ? '' : ' seval-main--left-collapsed'}`}>
|
<main className={`btd-main${leftOpen ? '' : ' seval-main--left-collapsed'}`}>
|
||||||
<div className="btd-main-content seval-main-content">
|
<div className="btd-main-content seval-main-content">
|
||||||
<StrategyEvaluationChart
|
<div className="seval-main-chart-area">
|
||||||
|
<StrategyEvaluationChart
|
||||||
market={market}
|
market={market}
|
||||||
timeframe={chartTimeframe}
|
timeframe={chartTimeframe}
|
||||||
timeframeChoice={timeframeChoice}
|
timeframeChoice={timeframeChoice}
|
||||||
@@ -1021,10 +1039,26 @@ function StrategyEvaluationPageInner({ theme = 'dark' }: Props) {
|
|||||||
overlayVisibility={overlayVisibility}
|
overlayVisibility={overlayVisibility}
|
||||||
onSetOverlayVisibility={handleSetOverlayVisibility}
|
onSetOverlayVisibility={handleSetOverlayVisibility}
|
||||||
/>
|
/>
|
||||||
<StrategyEvaluationStrategyPanel
|
</div>
|
||||||
strategy={selectedStrategy}
|
<div
|
||||||
editor={strategyEditor}
|
className="btd-splitter btd-splitter--h seval-strategy-splitter"
|
||||||
|
role="separator"
|
||||||
|
aria-orientation="horizontal"
|
||||||
|
aria-label="차트·전략 패널 높이 조절"
|
||||||
|
aria-valuemin={STRATEGY_PANEL_MIN}
|
||||||
|
aria-valuemax={STRATEGY_PANEL_MAX}
|
||||||
|
aria-valuenow={strategyPanelHeight}
|
||||||
|
onPointerDown={onStrategyPanelSplit}
|
||||||
/>
|
/>
|
||||||
|
<div
|
||||||
|
className="seval-strategy-panel-wrap"
|
||||||
|
style={{ height: strategyPanelHeight }}
|
||||||
|
>
|
||||||
|
<StrategyEvaluationStrategyPanel
|
||||||
|
strategy={selectedStrategy}
|
||||||
|
editor={strategyEditor}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|||||||
@@ -377,11 +377,37 @@
|
|||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.seval-main-content .seval-chart {
|
.seval-main-chart-area {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 140px;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seval-main-chart-area .seval-chart {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.seval-strategy-splitter {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin: 2px 0;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seval-strategy-panel-wrap {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seval-strategy-splitter.btd-splitter.se-splitter--active {
|
||||||
|
background: color-mix(in srgb, var(--btd-gold) 35%, var(--btd-divider));
|
||||||
|
}
|
||||||
|
|
||||||
.seval-chart {
|
.seval-chart {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -1273,10 +1299,8 @@
|
|||||||
/* ── 중앙 하단 — 목록 방식 전략 설정 ── */
|
/* ── 중앙 하단 — 목록 방식 전략 설정 ── */
|
||||||
.seval-strategy-panel {
|
.seval-strategy-panel {
|
||||||
position: relative;
|
position: relative;
|
||||||
flex: 0 0 min(40vh, 380px);
|
flex: 1;
|
||||||
min-height: 200px;
|
min-height: 0;
|
||||||
max-height: min(48vh, 440px);
|
|
||||||
margin-top: 6px;
|
|
||||||
border: 1px solid var(--se-terminal-border, rgba(255, 255, 255, 0.08));
|
border: 1px solid var(--se-terminal-border, rgba(255, 255, 255, 0.08));
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: var(--se-panel-card-bg, var(--se-terminal-bg, color-mix(in srgb, var(--bg) 92%, #000)));
|
background: var(--se-panel-card-bg, var(--se-terminal-bg, color-mix(in srgb, var(--bg) 92%, #000)));
|
||||||
@@ -1285,8 +1309,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.seval-strategy-panel--empty {
|
.seval-strategy-panel--empty {
|
||||||
flex: 0 0 auto;
|
flex: 1;
|
||||||
max-height: none;
|
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
padding: 12px 14px;
|
padding: 12px 14px;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user