diff --git a/src/pages/stock/Stock.css b/src/pages/stock/Stock.css index 3f6deb3..35c4686 100644 --- a/src/pages/stock/Stock.css +++ b/src/pages/stock/Stock.css @@ -3232,3 +3232,121 @@ display: none; } } + +/* ── 관심종목 탭 (Watchlist) ───────────────────────────────── */ +.wl-form { + display: flex; + flex-wrap: wrap; + gap: 8px; + align-items: center; +} +.wl-form__input { + flex: 1 1 140px; + min-width: 120px; + padding: 9px 12px; + border: 1px solid var(--line); + border-radius: 10px; + background: rgba(255, 255, 255, 0.03); + color: inherit; + font-size: 13px; +} +.wl-form__input:focus { + outline: none; + border-color: var(--accent-stock); +} + +.wl-list { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 8px; +} +.wl-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(148, 163, 184, 0.12); + border-radius: 10px; + padding: 10px 14px; +} +.wl-row__meta { + display: flex; + align-items: baseline; + flex-wrap: wrap; + gap: 8px; + min-width: 0; +} +.wl-row__name { font-size: 14px; } +.wl-row__ticker { font-size: 12px; color: var(--muted); } +.wl-row__note { font-size: 12px; color: var(--muted); opacity: 0.85; } +.wl-del { + flex: none; + border: none; + background: transparent; + color: #94a3b8; + cursor: pointer; + font-size: 14px; + line-height: 1; + padding: 4px 6px; + border-radius: 6px; +} +.wl-del:hover { color: #ef4444; background: rgba(239, 68, 68, 0.1); } + +.wl-period-toggle { display: flex; gap: 4px; } +.wl-period { + border: 1px solid var(--line); + background: transparent; + color: var(--muted); + border-radius: 8px; + padding: 4px 10px; + font-size: 12px; + cursor: pointer; +} +.wl-period.is-active { + color: var(--accent-stock); + border-color: var(--accent-stock); + background: rgba(148, 163, 184, 0.08); +} + +.wl-alerts { + display: flex; + flex-direction: column; + gap: 10px; +} +.wl-alert { + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(148, 163, 184, 0.12); + border-radius: 10px; + padding: 12px 14px; + display: flex; + flex-direction: column; + gap: 6px; +} +.wl-alert__head { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; +} +.wl-kind-badge { + font-size: 11px; + font-weight: 700; + padding: 2px 8px; + border-radius: 999px; +} +.wl-alert__name { font-size: 14px; } +.wl-alert__ticker { font-size: 12px; color: var(--muted); } +.wl-alert__time { font-size: 11px; color: var(--muted); margin-left: auto; } +.wl-alert__body { + display: flex; + align-items: baseline; + gap: 10px; + flex-wrap: wrap; +} +.wl-cond { font-size: 13px; font-weight: 600; } +.wl-alert__price { font-size: 13px; color: var(--muted); } +.wl-alert__detail { font-size: 12px; color: var(--muted); } diff --git a/src/pages/stock/components/WatchlistTab.jsx b/src/pages/stock/components/WatchlistTab.jsx new file mode 100644 index 0000000..aff97ab --- /dev/null +++ b/src/pages/stock/components/WatchlistTab.jsx @@ -0,0 +1,145 @@ +import React, { useState } from 'react'; +import Loading from '../../../components/Loading'; +import { kindMeta, conditionLabel, relativeTime } from '../watchlistUtils'; +import { formatNumber } from '../stockUtils'; + +const DAYS_OPTIONS = [ + { value: 1, label: '1D' }, + { value: 7, label: '7D' }, + { value: 30, label: '30D' }, +]; + +const AlertCard = ({ a }) => { + const meta = kindMeta(a.kind); + return ( +
관심종목
+등록한 종목은 매매 시그널 감시 유니버스에 포함됩니다.
+{wl.error}
} + + {wl.items.length === 0 ? ( +아직 관심종목이 없습니다. 종목코드를 추가해 보세요.
+ ) : ( +시그널
+감시 종목에서 발생한 매수·매도 시그널 이력입니다.
+{wl.alertError}
} + + {wl.alerts.length === 0 ? ( +해당 기간에 발생한 알림이 없습니다.
+ ) : ( +※ 어드바이저리 알림이며 자동매매가 아닙니다. 최종 판단은 본인 책임입니다.
+