매매 시그널 화면 추가 수정

This commit is contained in:
Macbook
2026-05-29 01:32:18 +09:00
parent 19ae5f5fae
commit 094a285363
5 changed files with 407 additions and 153 deletions
+74 -25
View File
@@ -9811,9 +9811,9 @@ html.theme-blue {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-start; justify-content: flex-start;
gap: clamp(4px, 1.2cqi, 10px); gap: clamp(3px, 1cqh, 10px);
overflow-y: auto; overflow: hidden;
overflow-x: hidden; overflow-y: hidden;
} }
.rsp-trade-card-body .top-field { .rsp-trade-card-body .top-field {
margin-bottom: 0; margin-bottom: 0;
@@ -9912,12 +9912,35 @@ html.theme-blue {
margin-bottom: 0; margin-bottom: 0;
} }
@container trade-card (max-height: 360px) { @container trade-card (max-height: 520px) {
.rsp-trade-card-body .top-order-kind {
flex-wrap: wrap;
row-gap: 3px;
}
.rsp-trade-card-body .top-kind-btn {
flex: 1 1 calc(33% - 4px);
min-width: 0;
padding: 3px 2px;
font-size: clamp(8px, 1.5cqh, 10px);
}
.rsp-trade-card-body .top-kind-btn--wide {
flex: 1 1 calc(50% - 4px);
}
}
@container trade-card (max-height: 440px) {
.rsp-trade-card-body .top-panel {
gap: 2px;
}
.rsp-trade-card-body .top-panel-fields {
gap: 2px;
}
.rsp-trade-card-body .top-price-qty-block { .rsp-trade-card-body .top-price-qty-block {
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
column-gap: 8px; column-gap: 6px;
row-gap: 4px; row-gap: 4px;
align-content: start;
} }
.rsp-trade-card-body .top-price-qty-block .top-field--price { .rsp-trade-card-body .top-price-qty-block .top-field--price {
grid-column: 1; grid-column: 1;
@@ -9932,14 +9955,58 @@ html.theme-blue {
grid-row: 2; grid-row: 2;
margin-top: 0; margin-top: 0;
} }
.rsp-trade-card-body .top-pct-row--block .top-pct-btn {
flex: 1 1 calc(25% - 3px);
min-width: 0;
padding: 2px 1px;
font-size: clamp(8px, 1.4cqh, 9px);
}
.rsp-trade-card-body .top-pct-row--block .top-pct-btn--direct {
flex: 1 1 calc(33% - 3px);
}
}
@container trade-card (max-height: 340px) {
.rsp-trade-card-body .top-paper-hint,
.rsp-trade-card-body .top-meta {
display: none;
}
.rsp-trade-card-body .top-label-help {
display: none;
}
.rsp-trade-card-body .top-panel--buy .top-field:has(.top-symbol-field) {
display: none;
}
.rsp-trade-card-body .top-reset {
padding: 4px 8px;
font-size: 11px;
}
.rsp-trade-card-body .top-submit {
padding: 5px 8px;
font-size: 12px;
}
}
@media (max-height: 820px) {
.rsp-trade-stack {
gap: 6px;
padding: 6px 8px 4px;
}
.rsp-trade-card-title {
padding: 4px 10px 3px;
font-size: 11px;
}
} }
@media (max-height: 780px) { @media (max-height: 780px) {
@supports not (container-type: size) { @supports not (container-type: size) {
.rsp-trade-card-body .top-panel-fields {
overflow: hidden;
}
.rsp-trade-card-body .top-price-qty-block { .rsp-trade-card-body .top-price-qty-block {
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
column-gap: 8px; column-gap: 6px;
row-gap: 4px; row-gap: 4px;
} }
.rsp-trade-card-body .top-price-qty-block .top-field--price { .rsp-trade-card-body .top-price-qty-block .top-field--price {
@@ -11467,28 +11534,10 @@ html.theme-light .tam-disclaimer { color: #90a4ae; }
height: 100%; height: 100%;
} }
/* 매매 시그널 알림 우측: 좁은 카드에서도 주문 비율·총액이 겹치지 않도록 */ /* 매매 시그널 알림 우측 — 가상매매·실시간 차트와 동일 compact (paperDashboard.css) */
.tnl-page--with-right .ptd-split-panel--right .ptd-order-card > .top-panel {
justify-content: flex-start;
}
.tnl-page--with-right .ptd-split-panel--right .ptd-order-card .top-panel-fields {
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
justify-content: flex-start;
}
.tnl-page--with-right .ptd-split-panel--right .ptd-order-card .top-price-qty-block {
flex: 0 0 auto;
justify-content: flex-start;
}
.tnl-page--with-right .ptd-split-panel--right .ptd-order-card .top-actions { .tnl-page--with-right .ptd-split-panel--right .ptd-order-card .top-actions {
margin-top: auto; margin-top: auto;
} }
@container trade-card (max-height: 400px) {
.tnl-page--with-right .ptd-split-panel--right .ptd-order-card .top-meta {
font-size: 9px;
}
}
.tnl-row--selected { .tnl-row--selected {
border-color: var(--accent, #7aa2f7); border-color: var(--accent, #7aa2f7);
box-shadow: 0 0 0 1px rgba(122, 162, 247, 0.35); box-shadow: 0 0 0 1px rgba(122, 162, 247, 0.35);
@@ -37,6 +37,8 @@ const TradeNotificationHScrollPane: React.FC<TradeNotificationHScrollPaneProps>
const syncScrollState = useCallback(() => { const syncScrollState = useCallback(() => {
const el = viewportRef.current; const el = viewportRef.current;
if (!el) return; if (!el) return;
const pageWidth = Math.max(160, el.clientWidth - 20);
el.style.setProperty('--tnl-hscroll-page-width', `${pageWidth}px`);
const max = Math.max(0, el.scrollWidth - el.clientWidth); const max = Math.max(0, el.scrollWidth - el.clientWidth);
const overflow = max > 2; const overflow = max > 2;
setCanScroll(overflow); setCanScroll(overflow);
@@ -61,7 +63,8 @@ const TradeNotificationHScrollPane: React.FC<TradeNotificationHScrollPaneProps>
const scrollByStep = useCallback((dir: -1 | 1) => { const scrollByStep = useCallback((dir: -1 | 1) => {
const el = viewportRef.current; const el = viewportRef.current;
if (!el) return; if (!el) return;
const step = Math.max(120, Math.round(el.clientWidth * SCROLL_STEP_RATIO)); const pageWidth = Math.max(120, el.clientWidth - 20);
const step = Math.max(120, Math.round(pageWidth * SCROLL_STEP_RATIO));
el.scrollBy({ left: dir * step, behavior: 'smooth' }); el.scrollBy({ left: dir * step, behavior: 'smooth' });
}, []); }, []);
@@ -1,5 +1,5 @@
/** /**
* 매매 시그널 알림 목록 행 — 좌: 요약 카드(고정) · 우: 캔들+지표 카드(가로 스크롤) * 매매 시그널 알림 목록 행 — 4칸이 목록 너비를 꽉 채움, 보조지표 2개↑ 시 우측 슬롯만 스크롤
*/ */
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import type { Theme } from '../../types'; import type { Theme } from '../../types';
@@ -174,28 +174,10 @@ const TradeNotificationListRow: React.FC<Props> = ({
]); ]);
const receiving = useLiveReceiveFlash(receiveSignal, liveReceiveEnabled); const receiving = useLiveReceiveFlash(receiveSignal, liveReceiveEnabled);
/** 차트 영역 카드 수 — 알림상세(1) : 차트카드(N) 동일 비율 배분용 */ const indicatorChartCount = indicatorCards.length;
const chartCardCount = useMemo(() => { /** 보조지표 2개 이상이면 첫 1개만 보이고 나머지는 좌우 스크롤 */
if (!isListLayout) return 0; const indicatorScrollNeeded = indicatorChartCount >= 2;
if (chartExpanded) return 1; const indicatorPlaceholder = item.strategyId != null && indicatorChartCount === 0 && chartActive;
let n = 1;
if (signalActive) n += 1;
n += indicatorCards.length;
if (item.strategyId != null && indicatorCards.length === 0 && chartActive) n += 1;
return n;
}, [
isListLayout,
chartExpanded,
signalActive,
indicatorCards.length,
item.strategyId,
chartActive,
]);
const rowGalleryStyle = useMemo(
() => ({ '--tnl-chart-card-count': String(chartCardCount) }) as React.CSSProperties,
[chartCardCount],
);
const handleRowClick = useCallback((e: React.MouseEvent) => { const handleRowClick = useCallback((e: React.MouseEvent) => {
const t = e.target as HTMLElement; const t = e.target as HTMLElement;
@@ -324,7 +306,6 @@ const TradeNotificationListRow: React.FC<Props> = ({
> >
<div <div
className={['tnl-row-gallery', chartExpanded ? 'tnl-row-gallery--chart-expanded' : ''].filter(Boolean).join(' ')} className={['tnl-row-gallery', chartExpanded ? 'tnl-row-gallery--chart-expanded' : ''].filter(Boolean).join(' ')}
style={rowGalleryStyle}
> >
<TradeNotificationHScrollPane <TradeNotificationHScrollPane
className="tnl-row-gallery-detail" className="tnl-row-gallery-detail"
@@ -333,11 +314,11 @@ const TradeNotificationListRow: React.FC<Props> = ({
{summaryCard} {summaryCard}
</TradeNotificationHScrollPane> </TradeNotificationHScrollPane>
<TradeNotificationHScrollPane
className={['tnl-row-gallery-charts', chartExpanded ? 'tnl-row-gallery-charts--expanded' : ''].filter(Boolean).join(' ')}
label={chartExpanded ? '차트 전체보기' : '신호·캔들·지표'}
>
{chartExpanded ? ( {chartExpanded ? (
<TradeNotificationHScrollPane
className="tnl-row-gallery-indicators tnl-row-gallery-indicators--expanded"
label="차트 전체보기"
>
<div className="tnl-charts-expanded-inner"> <div className="tnl-charts-expanded-inner">
{expandedChartKey === 'candle' && ( {expandedChartKey === 'candle' && (
<TradeSignalChartCard <TradeSignalChartCard
@@ -370,9 +351,14 @@ const TradeNotificationListRow: React.FC<Props> = ({
/> />
)} )}
</div> </div>
</TradeNotificationHScrollPane>
) : ( ) : (
<div className="tnl-charts-track"> <>
{signalActive && ( {signalActive && (
<TradeNotificationHScrollPane
className="tnl-row-gallery-signal"
label="신호 일치율"
>
<TradeNotificationSignalCard <TradeNotificationSignalCard
market={item.market} market={item.market}
strategyId={item.strategyId} strategyId={item.strategyId}
@@ -388,8 +374,10 @@ const TradeNotificationListRow: React.FC<Props> = ({
signalLoading={signalLoading} signalLoading={signalLoading}
onExpandCharts={() => setExpandedChartKey('candle')} onExpandCharts={() => setExpandedChartKey('candle')}
/> />
</TradeNotificationHScrollPane>
)} )}
<div className="tnl-row-gallery-candle" aria-label="캔들 차트">
<TradeSignalChartCard <TradeSignalChartCard
label="캔들" label="캔들"
meta={candleKo} meta={candleKo}
@@ -403,7 +391,16 @@ const TradeNotificationListRow: React.FC<Props> = ({
onRestore={() => setExpandedChartKey(null)} onRestore={() => setExpandedChartKey(null)}
onRealtimeActivity={chartActive ? bumpChartActivity : undefined} onRealtimeActivity={chartActive ? bumpChartActivity : undefined}
/> />
</div>
<TradeNotificationHScrollPane
className={[
'tnl-row-gallery-indicators',
indicatorScrollNeeded ? 'tnl-row-gallery-indicators--scroll' : '',
].filter(Boolean).join(' ')}
label="보조지표"
>
<div className="tnl-charts-track tnl-charts-track--indicators-only">
{indicatorCards.map(card => ( {indicatorCards.map(card => (
<TradeSignalChartCard <TradeSignalChartCard
key={card.id} key={card.id}
@@ -421,14 +418,15 @@ const TradeNotificationListRow: React.FC<Props> = ({
/> />
))} ))}
{item.strategyId != null && indicatorCards.length === 0 && chartActive && ( {indicatorPlaceholder && (
<section className="tnl-chart-card tnl-chart-card--placeholder"> <section className="tnl-chart-card tnl-chart-card--placeholder">
<p className="tnl-muted"> </p> <p className="tnl-muted"> </p>
</section> </section>
)} )}
</div> </div>
)}
</TradeNotificationHScrollPane> </TradeNotificationHScrollPane>
</>
)}
</div> </div>
</li> </li>
); );
+123 -17
View File
@@ -121,6 +121,8 @@
border-radius: 10px; border-radius: 10px;
background: color-mix(in srgb, var(--se-bg-elevated, var(--bg2)) 88%, transparent); background: color-mix(in srgb, var(--se-bg-elevated, var(--bg2)) 88%, transparent);
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--se-text, var(--text)) 4%, transparent); box-shadow: inset 0 1px 0 color-mix(in srgb, var(--se-text, var(--text)) 4%, transparent);
container-type: size;
container-name: split-trade-card;
} }
.ptd-split-card-head { .ptd-split-card-head {
flex-shrink: 0; flex-shrink: 0;
@@ -270,6 +272,12 @@
padding: 4px 8px 6px; padding: 4px 8px 6px;
} }
.ptd-split-panel--right .ptd-split-card-body:has(.ptd-order-card) {
overflow: hidden;
overflow-y: hidden;
padding: 3px 6px 4px;
}
.ptd-split-panel--right .ptd-split-card-body > .ptd-order-card, .ptd-split-panel--right .ptd-split-card-body > .ptd-order-card,
.ptd-split-panel--right .ptd-split-card-body > .top-panel { .ptd-split-panel--right .ptd-split-card-body > .top-panel {
flex: 1 1 0; flex: 1 1 0;
@@ -298,9 +306,9 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-start; justify-content: flex-start;
gap: clamp(4px, 1.2cqh, 10px); gap: clamp(3px, 1cqh, 10px);
overflow-y: auto; overflow: hidden;
overflow-x: hidden; overflow-y: hidden;
} }
.ptd-split-panel--right .ptd-order-card .top-paper-hint { .ptd-split-panel--right .ptd-order-card .top-paper-hint {
@@ -683,33 +691,131 @@
} }
} }
@container trade-card (max-height: 360px) { /* ── 우측 매수·매도 카드: 낮은 높이에서 카드 내 스크롤 없이 압축 레이아웃 ── */
.ptd-split-panel--right .ptd-order-card > .top-panel { @container trade-card (max-height: 520px) {
gap: 3px; .ptd-split-panel--right .ptd-order-card .top-order-kind {
flex-wrap: wrap;
row-gap: 3px;
} }
.ptd-order-card .top-price-qty-block { .ptd-split-panel--right .ptd-order-card .top-kind-btn {
flex: 1 1 calc(33% - 4px);
min-width: 0;
padding: 3px 2px;
font-size: clamp(8px, 1.5cqh, 10px);
}
.ptd-split-panel--right .ptd-order-card .top-kind-btn--wide {
flex: 1 1 calc(50% - 4px);
}
}
@container trade-card (max-height: 440px) {
.ptd-split-panel--right .ptd-order-card > .top-panel {
gap: 2px;
}
.ptd-split-panel--right .ptd-order-card .top-panel-fields {
gap: 2px;
}
.ptd-order-card .top-price-qty-block,
.ptd-split-panel--right .ptd-order-card .top-price-qty-block {
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
column-gap: 8px; column-gap: 6px;
row-gap: 6px; row-gap: 4px;
align-content: start; align-content: start;
} }
.ptd-order-card .top-price-qty-block .top-field--price { grid-column: 1; grid-row: 1; } .ptd-order-card .top-price-qty-block .top-field--price,
.ptd-order-card .top-price-qty-block .top-field--qty { grid-column: 2; grid-row: 1; } .ptd-split-panel--right .ptd-order-card .top-price-qty-block .top-field--price {
.ptd-order-card .top-price-qty-block .top-pct-row--block { grid-column: 1 / -1; grid-row: 2; margin-top: 0; } grid-column: 1;
grid-row: 1;
}
.ptd-order-card .top-price-qty-block .top-field--qty,
.ptd-split-panel--right .ptd-order-card .top-price-qty-block .top-field--qty {
grid-column: 2;
grid-row: 1;
}
.ptd-order-card .top-price-qty-block .top-pct-row--block,
.ptd-split-panel--right .ptd-order-card .top-price-qty-block .top-pct-row--block {
grid-column: 1 / -1;
grid-row: 2;
margin-top: 0;
}
.ptd-split-panel--right .ptd-order-card .top-pct-row--block .top-pct-btn {
flex: 1 1 calc(25% - 3px);
min-width: 0;
padding: 2px 1px;
font-size: clamp(8px, 1.4cqh, 9px);
}
.ptd-split-panel--right .ptd-order-card .top-pct-row--block .top-pct-btn--direct {
flex: 1 1 calc(33% - 3px);
}
}
@container trade-card (max-height: 340px) {
.ptd-split-panel--right .ptd-order-card .top-paper-hint,
.ptd-split-panel--right .ptd-order-card .top-meta {
display: none;
}
.ptd-split-panel--right .ptd-order-card .top-label-help {
display: none;
}
.ptd-split-panel--right .ptd-order-card .top-panel--buy .top-field:has(.top-symbol-field) {
display: none;
}
.ptd-split-panel--right .ptd-order-card .top-reset {
padding: 4px 8px;
font-size: 11px;
}
.ptd-split-panel--right .ptd-order-card .top-submit {
padding: 5px 8px;
font-size: 12px;
}
}
@container split-trade-card (max-height: 200px) {
.ptd-split-panel--right .ptd-split-card-head {
padding: 3px 8px;
font-size: 10px;
}
}
@media (max-height: 820px) {
.ptd-split-panel--right .ptd-split-card-head {
padding: 4px 8px;
font-size: 10px;
}
.ptd-split-panel--right .ptd-split-card-body:has(.ptd-order-card) {
padding: 2px 5px 3px;
}
} }
@media (max-height: 780px) { @media (max-height: 780px) {
@supports not (container-type: size) { @supports not (container-type: size) {
.ptd-order-card .top-price-qty-block { .ptd-order-card .top-price-qty-block,
.ptd-split-panel--right .ptd-order-card .top-price-qty-block {
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
column-gap: 8px; column-gap: 6px;
row-gap: 4px; row-gap: 4px;
} }
.ptd-order-card .top-price-qty-block .top-field--price { grid-column: 1; grid-row: 1; } .ptd-order-card .top-price-qty-block .top-field--price,
.ptd-order-card .top-price-qty-block .top-field--qty { grid-column: 2; grid-row: 1; } .ptd-split-panel--right .ptd-order-card .top-price-qty-block .top-field--price {
.ptd-order-card .top-price-qty-block .top-pct-row--block { grid-column: 1 / -1; grid-row: 2; margin-top: 0; } grid-column: 1;
grid-row: 1;
}
.ptd-order-card .top-price-qty-block .top-field--qty,
.ptd-split-panel--right .ptd-order-card .top-price-qty-block .top-field--qty {
grid-column: 2;
grid-row: 1;
}
.ptd-order-card .top-price-qty-block .top-pct-row--block,
.ptd-split-panel--right .ptd-order-card .top-price-qty-block .top-pct-row--block {
grid-column: 1 / -1;
grid-row: 2;
margin-top: 0;
}
.ptd-split-panel--right .ptd-order-card .top-panel-fields {
overflow: hidden;
}
} }
} }
+150 -52
View File
@@ -54,8 +54,11 @@
box-sizing: border-box; box-sizing: border-box;
} }
/* 목록 한 줄 = 알림상세 · 신호일치율 · 캔들 · 보조지표(1칸) — 가로 100% 꽉 참 */
.tnl-row-gallery { .tnl-row-gallery {
--tnl-summary-card-width: 320px; --tnl-summary-card-width: 320px;
--tnl-signal-slot-width: 300px;
--tnl-chart-card-width: 280px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: stretch; align-items: stretch;
@@ -67,28 +70,66 @@
box-sizing: border-box; box-sizing: border-box;
} }
/* 좌측 알림 요약 카드 — 고정 너비(모든 행 동일) · 우측은 차트 영역이 나머지 공간 사용 */
.tnl-row-gallery-detail { .tnl-row-gallery-detail {
flex: 0 0 var(--tnl-summary-card-width); flex: 1.15 1 0;
width: var(--tnl-summary-card-width); min-width: 0;
min-width: var(--tnl-summary-card-width);
max-width: var(--tnl-summary-card-width);
} }
.tnl-row-gallery-charts { .tnl-row-gallery-signal {
flex: 1 1 0; flex: 1 1 0;
min-width: 0; min-width: 0;
width: auto; }
.tnl-row-gallery-candle {
flex: 1 1 0;
min-width: 0;
height: 300px;
max-height: 300px;
display: flex;
flex-direction: column;
align-items: stretch;
border-radius: 12px;
border: 1px solid var(--se-border, var(--border));
background: color-mix(in srgb, var(--bg) 40%, var(--bg2));
overflow: hidden;
box-sizing: border-box;
}
.tnl-row-gallery-candle > .tnl-chart-card {
flex: 1 1 auto;
width: 100%;
min-width: 0;
max-width: none;
height: 100%;
max-height: 100%;
border: none;
border-radius: 0;
}
.tnl-row-gallery-indicators {
flex: 1 1 0;
min-width: 0;
}
.tnl-row-gallery > .tnl-hscroll-pane,
.tnl-row-gallery > .tnl-row-gallery-candle {
height: 300px;
max-height: 300px;
}
.tnl-row-gallery .tnl-chart-card {
height: 100%;
max-height: 100%;
} }
.tnl-row-gallery--chart-expanded .tnl-row-gallery-detail { .tnl-row-gallery--chart-expanded .tnl-row-gallery-detail {
flex: 0 0 var(--tnl-summary-card-width); flex: 0 0 min(28%, var(--tnl-summary-card-width));
width: var(--tnl-summary-card-width); width: min(28%, var(--tnl-summary-card-width));
min-width: var(--tnl-summary-card-width); min-width: min(240px, var(--tnl-summary-card-width));
max-width: var(--tnl-summary-card-width); max-width: var(--tnl-summary-card-width);
} }
.tnl-row-gallery--chart-expanded .tnl-row-gallery-charts { .tnl-row-gallery--chart-expanded .tnl-row-gallery-indicators {
flex: 1 1 0; flex: 1 1 0;
min-width: 0; min-width: 0;
} }
@@ -139,12 +180,39 @@
box-sizing: border-box; box-sizing: border-box;
} }
.tnl-row-gallery-charts .tnl-hscroll-pane__content { .tnl-row-gallery-signal .tnl-hscroll-pane__viewport {
overflow-x: hidden;
}
.tnl-row-gallery-signal .tnl-hscroll-pane__content {
width: 100%;
min-width: 100%;
}
.tnl-row-gallery-indicators--scroll .tnl-hscroll-pane__viewport {
overflow-x: auto;
}
.tnl-row-gallery-indicators--scroll .tnl-hscroll-pane__content {
width: max-content;
min-width: max-content;
}
.tnl-row-gallery-indicators:not(.tnl-row-gallery-indicators--scroll) .tnl-hscroll-pane__viewport {
overflow-x: hidden;
}
.tnl-row-gallery-indicators:not(.tnl-row-gallery-indicators--scroll) .tnl-hscroll-pane__content {
width: 100%;
min-width: 100%;
}
.tnl-row-gallery-indicators--expanded .tnl-hscroll-pane__content {
min-width: 100%; min-width: 100%;
width: 100%; width: 100%;
} }
.tnl-row-gallery-charts .tnl-hscroll-pane__viewport { .tnl-row-gallery-indicators--expanded .tnl-hscroll-pane__viewport {
overflow-x: hidden; overflow-x: hidden;
} }
@@ -217,12 +285,12 @@
height: 100%; height: 100%;
} }
/* 신호상세 — 가상매매 vtd-card 슬롯 (차트보다 좁게 · 나머지는 캔들·지표) */ /* 신호상세 — 갤러리 행에서는 슬롯 너비 100% */
.tnl-signal-slot { .tnl-signal-slot {
flex: 1.05 1 272px; flex: 0 0 var(--tnl-signal-slot-width);
width: auto; width: var(--tnl-signal-slot-width);
min-width: min(100%, 272px); min-width: var(--tnl-signal-slot-width);
max-width: 34%; max-width: var(--tnl-signal-slot-width);
height: 280px; height: 280px;
max-height: 280px; max-height: 280px;
display: flex; display: flex;
@@ -231,6 +299,15 @@
box-sizing: border-box; box-sizing: border-box;
} }
.tnl-row-gallery-signal .tnl-signal-slot {
flex: 1 1 auto;
width: 100%;
min-width: 0;
max-width: none;
height: 100%;
max-height: 100%;
}
.tnl-signal-slot .tnl-signal-summary--embedded-wrap { .tnl-signal-slot .tnl-signal-summary--embedded-wrap {
flex: 1; flex: 1;
min-height: 0; min-height: 0;
@@ -323,12 +400,6 @@
flex-shrink: 0; flex-shrink: 0;
} }
.tnl-charts-track > .tnl-signal-slot {
flex: 1.05 1 272px;
min-width: min(100%, 272px);
max-width: 34%;
}
/* 가상매매 투자대상 카드(vtd)와 동일한 3단 구성 */ /* 가상매매 투자대상 카드(vtd)와 동일한 3단 구성 */
.tnl-summary-card { .tnl-summary-card {
flex: 1 1 auto; flex: 1 1 auto;
@@ -605,11 +676,6 @@
box-sizing: border-box; box-sizing: border-box;
} }
.tnl-row-gallery-charts--expanded .tnl-hscroll-pane__content {
min-width: 100%;
width: 100%;
}
.tnl-charts-expanded-inner .tnl-chart-card--expanded { .tnl-charts-expanded-inner .tnl-chart-card--expanded {
flex: 1; flex: 1;
width: 100%; width: 100%;
@@ -629,22 +695,56 @@
padding: 10px; padding: 10px;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: max-content;
min-width: 0; min-width: max-content;
flex-shrink: 0;
} }
.tnl-charts-track > .tnl-chart-card { .tnl-charts-track > .tnl-chart-card {
flex: 1.12 1 0; flex: 0 0 var(--tnl-chart-card-width);
width: 0; width: var(--tnl-chart-card-width);
min-width: var(--tnl-chart-card-width);
max-width: var(--tnl-chart-card-width);
}
/* 보조지표 1개 — 슬롯 너비 100% 채움 */
.tnl-row-gallery-indicators:not(.tnl-row-gallery-indicators--scroll) .tnl-charts-track--indicators-only {
width: 100%;
min-width: 100%;
max-width: 100%;
}
.tnl-row-gallery-indicators:not(.tnl-row-gallery-indicators--scroll) .tnl-charts-track--indicators-only > .tnl-chart-card,
.tnl-row-gallery-indicators:not(.tnl-row-gallery-indicators--scroll) .tnl-charts-track--indicators-only > .tnl-chart-card--placeholder {
flex: 1 1 auto;
width: 100%;
min-width: 0; min-width: 0;
max-width: none; max-width: none;
} }
/* 보조지표 2개↑ — 우측 슬롯 안에서만 스크롤, 페이지당 1장 = 슬롯 너비 */
.tnl-row-gallery-indicators--scroll .tnl-charts-track--indicators-only {
width: max-content;
min-width: max-content;
}
.tnl-row-gallery-indicators--scroll .tnl-charts-track--indicators-only > .tnl-chart-card {
flex: 0 0 var(--tnl-hscroll-page-width, 240px);
width: var(--tnl-hscroll-page-width, 240px);
min-width: var(--tnl-hscroll-page-width, 240px);
max-width: var(--tnl-hscroll-page-width, 240px);
flex-shrink: 0;
}
.tnl-charts-track--indicators-only:not(:has(.tnl-chart-card)) {
min-width: 100%;
}
.tnl-chart-card { .tnl-chart-card {
position: relative; position: relative;
flex: 1 1 0; flex: 0 0 var(--tnl-chart-card-width);
width: 0; width: var(--tnl-chart-card-width);
min-width: 0; min-width: var(--tnl-chart-card-width);
height: 280px; height: 280px;
max-height: 280px; max-height: 280px;
display: flex; display: flex;
@@ -1076,12 +1176,14 @@ ul.tnl-list.tnl-list--grid {
max-width: var(--tnl-summary-card-width); max-width: var(--tnl-summary-card-width);
} }
.tnl-row-gallery-charts, .tnl-row-gallery-detail,
.tnl-row-gallery--chart-expanded .tnl-row-gallery-charts { .tnl-row-gallery-signal,
.tnl-row-gallery-candle,
.tnl-row-gallery-indicators {
flex: 1 1 auto; flex: 1 1 auto;
width: 100%; width: 100%;
max-width: 100%;
min-width: 0; min-width: 0;
max-width: 100%;
} }
.tnl-hscroll-pane { .tnl-hscroll-pane {
@@ -1089,10 +1191,6 @@ ul.tnl-list.tnl-list--grid {
max-height: 300px; max-height: 300px;
} }
.tnl-row-gallery-charts .tnl-hscroll-pane__viewport {
overflow-x: auto;
}
.tnl-summary-card { .tnl-summary-card {
min-width: 0; min-width: 0;
width: 100%; width: 100%;
@@ -1100,16 +1198,16 @@ ul.tnl-list.tnl-list--grid {
max-height: none; max-height: none;
} }
.tnl-charts-track { .tnl-row-gallery-signal .tnl-signal-slot,
min-width: max-content; .tnl-charts-track > .tnl-chart-card {
width: max-content; flex: 0 0 min(var(--tnl-chart-card-width), 88vw);
width: min(var(--tnl-chart-card-width), 88vw);
min-width: min(var(--tnl-chart-card-width), 88vw);
} }
.tnl-charts-track > .tnl-chart-card, .tnl-row-gallery-signal .tnl-signal-slot {
.tnl-charts-track > .tnl-signal-slot { flex: 0 0 min(var(--tnl-signal-slot-width), 88vw);
flex: 0 0 min(300px, 88vw); width: min(var(--tnl-signal-slot-width), 88vw);
width: min(300px, 88vw); min-width: min(var(--tnl-signal-slot-width), 88vw);
min-width: min(300px, 88vw);
max-width: none;
} }
} }