feat(chart): split toolbar into indicators row + actions row
When showSma is true, the indicator chips (MA5/20/60 + RSI + MACD) and the action buttons (수평선 / CSV / 전체화면, plus the fullscreen symbol label) were sharing one flex-wrap row. On narrow widths the actions wrapped into the middle of the indicators because `ml-auto` only enforces right-pull while everything fits on one line — once wrap kicks in the right-side group loses its anchor. Split into two rows so wrap in either group stays local: - Indicators row: rendered only when showSma. Hidden in 1D (intraday) where none of these are meaningful, matching prior behavior. - Actions row: always rendered. Leading fullscreen label + `ml-auto` to push the three action buttons right; on narrow widths they wrap among themselves without colliding with indicator chips.
This commit is contained in:
@@ -929,11 +929,80 @@ export function StockChart({ chart, prediction, targets }: Props) {
|
||||
|
||||
return (
|
||||
<div ref={wrapperRef} className={wrapperCls}>
|
||||
{/*
|
||||
툴바를 2 그룹으로 분리:
|
||||
A) 보조지표 (MA5/20/60 + RSI + MACD) — 일봉 계열에서만 의미. 안 보이면 row 자체 생략.
|
||||
B) 액션 (전체화면 종목 라벨 + 수평선 + CSV + 전체화면 토글) — 항상 표시.
|
||||
같은 줄에 다 묶었을 때 모바일/좁은 폭에서 indicators 와 actions 가 섞여서 wrap 되며
|
||||
"ml-auto" 가 줄바꿈 직전에서만 분리 효과를 주고 그 외엔 actions 가 indicators 사이로 끼어듦.
|
||||
분리하면 indicators wrap 은 indicators 안에서만 일어남 — actions 그룹은 자체 정렬 유지.
|
||||
*/}
|
||||
{showSma && (
|
||||
<div className="mb-1 flex flex-wrap items-center gap-1.5 px-1">
|
||||
{SMA_PRESETS.map((p) => {
|
||||
const on = active.has(p.window);
|
||||
return (
|
||||
<button
|
||||
key={p.window}
|
||||
type="button"
|
||||
onClick={() => toggle(p.window)}
|
||||
className={`flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10px] transition ${
|
||||
on
|
||||
? "border-zinc-600 bg-zinc-800/80 text-zinc-100"
|
||||
: "border-zinc-800 bg-transparent text-zinc-500 hover:text-zinc-300"
|
||||
}`}
|
||||
aria-pressed={on}
|
||||
>
|
||||
<span
|
||||
className="inline-block h-2 w-2 rounded-full"
|
||||
style={{ backgroundColor: on ? p.color : "transparent", border: `1px solid ${p.color}` }}
|
||||
/>
|
||||
{p.label}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
<span className="mx-1 text-zinc-700">|</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setRsiOn((v) => !v)}
|
||||
className={`flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10px] transition ${
|
||||
rsiOn
|
||||
? "border-zinc-600 bg-zinc-800/80 text-zinc-100"
|
||||
: "border-zinc-800 bg-transparent text-zinc-500 hover:text-zinc-300"
|
||||
}`}
|
||||
aria-pressed={rsiOn}
|
||||
title="상대강도지수 (Relative Strength Index, 14일)"
|
||||
>
|
||||
<span
|
||||
className="inline-block h-2 w-2 rounded-full"
|
||||
style={{ backgroundColor: rsiOn ? "#e879f9" : "transparent", border: "1px solid #e879f9" }}
|
||||
/>
|
||||
RSI
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setMacdOn((v) => !v)}
|
||||
className={`flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10px] transition ${
|
||||
macdOn
|
||||
? "border-zinc-600 bg-zinc-800/80 text-zinc-100"
|
||||
: "border-zinc-800 bg-transparent text-zinc-500 hover:text-zinc-300"
|
||||
}`}
|
||||
aria-pressed={macdOn}
|
||||
title="MACD (12/26/9) — 추세 전환 신호"
|
||||
>
|
||||
<span
|
||||
className="inline-block h-2 w-2 rounded-full"
|
||||
style={{ backgroundColor: macdOn ? "#60a5fa" : "transparent", border: "1px solid #60a5fa" }}
|
||||
/>
|
||||
MACD
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<div className="mb-1 flex flex-wrap items-center gap-1.5 px-1">
|
||||
{/*
|
||||
전체화면 모드 한정 종목 라벨 — 일반 모드는 위에 PriceHero 가 종목명/코드를 크게 보여주지만
|
||||
fullscreen 은 fixed inset 으로 PriceHero 가 가려져서 무슨 종목 차트인지 식별이 어려워짐.
|
||||
툴바 leading 자리에 작은 라벨을 끼워 시각적 노이즈 최소로 보완.
|
||||
actions row leading 자리에 작은 라벨을 끼워 시각적 노이즈 최소로 보완.
|
||||
(캔버스 위의 CrosshairLabel 과 위치 겹치지 않도록 캔버스가 아닌 툴바에 둠.)
|
||||
*/}
|
||||
{fullscreen && (
|
||||
@@ -942,67 +1011,6 @@ export function StockChart({ chart, prediction, targets }: Props) {
|
||||
<span className="font-mono text-[10px] text-zinc-500">{chart.code}</span>
|
||||
</span>
|
||||
)}
|
||||
{showSma && (
|
||||
<>
|
||||
{SMA_PRESETS.map((p) => {
|
||||
const on = active.has(p.window);
|
||||
return (
|
||||
<button
|
||||
key={p.window}
|
||||
type="button"
|
||||
onClick={() => toggle(p.window)}
|
||||
className={`flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10px] transition ${
|
||||
on
|
||||
? "border-zinc-600 bg-zinc-800/80 text-zinc-100"
|
||||
: "border-zinc-800 bg-transparent text-zinc-500 hover:text-zinc-300"
|
||||
}`}
|
||||
aria-pressed={on}
|
||||
>
|
||||
<span
|
||||
className="inline-block h-2 w-2 rounded-full"
|
||||
style={{ backgroundColor: on ? p.color : "transparent", border: `1px solid ${p.color}` }}
|
||||
/>
|
||||
{p.label}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
<span className="mx-1 text-zinc-700">|</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setRsiOn((v) => !v)}
|
||||
className={`flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10px] transition ${
|
||||
rsiOn
|
||||
? "border-zinc-600 bg-zinc-800/80 text-zinc-100"
|
||||
: "border-zinc-800 bg-transparent text-zinc-500 hover:text-zinc-300"
|
||||
}`}
|
||||
aria-pressed={rsiOn}
|
||||
title="상대강도지수 (Relative Strength Index, 14일)"
|
||||
>
|
||||
<span
|
||||
className="inline-block h-2 w-2 rounded-full"
|
||||
style={{ backgroundColor: rsiOn ? "#e879f9" : "transparent", border: "1px solid #e879f9" }}
|
||||
/>
|
||||
RSI
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setMacdOn((v) => !v)}
|
||||
className={`flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10px] transition ${
|
||||
macdOn
|
||||
? "border-zinc-600 bg-zinc-800/80 text-zinc-100"
|
||||
: "border-zinc-800 bg-transparent text-zinc-500 hover:text-zinc-300"
|
||||
}`}
|
||||
aria-pressed={macdOn}
|
||||
title="MACD (12/26/9) — 추세 전환 신호"
|
||||
>
|
||||
<span
|
||||
className="inline-block h-2 w-2 rounded-full"
|
||||
style={{ backgroundColor: macdOn ? "#60a5fa" : "transparent", border: "1px solid #60a5fa" }}
|
||||
/>
|
||||
MACD
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
|
||||
Reference in New Issue
Block a user