알림팝업 전체닫기 오류 수정
This commit is contained in:
+27
-24
@@ -29,7 +29,8 @@
|
||||
}
|
||||
|
||||
/* ── Dark Theme: 도쿄 나이트 (THEME_SETTINGS.md §2.2) ───────────── */
|
||||
.app.dark {
|
||||
.app.dark,
|
||||
html.theme-dark {
|
||||
--bg: #1a1b26;
|
||||
--bg1: #1a1b26;
|
||||
--bg2: #24283b;
|
||||
@@ -48,7 +49,8 @@
|
||||
}
|
||||
|
||||
/* ── Light Theme (THEME_SETTINGS.md §2.1) ──────────────────────── */
|
||||
.app.light {
|
||||
.app.light,
|
||||
html.theme-light {
|
||||
--bg: #f5f5f5;
|
||||
--bg1: #f5f5f5;
|
||||
--bg2: #ffffff;
|
||||
@@ -67,7 +69,8 @@
|
||||
}
|
||||
|
||||
/* ── Blue Theme: 딥 네이비 (THEME_SETTINGS.md §2.3) ─────────────── */
|
||||
.app.blue {
|
||||
.app.blue,
|
||||
html.theme-blue {
|
||||
--bg: #0c1929;
|
||||
--bg1: #0c1929;
|
||||
--bg2: #15273d;
|
||||
@@ -9412,32 +9415,32 @@
|
||||
}
|
||||
|
||||
/* ── 라이트 테마 오버라이드 ── */
|
||||
.app.light .tam-modal {
|
||||
html.theme-light .tam-modal {
|
||||
background: #ffffff;
|
||||
border-color: rgba(25,118,210,0.35);
|
||||
color: #212121;
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.18), 0 0 40px rgba(25,118,210,0.08);
|
||||
}
|
||||
.app.light .tam-header { background: #f5f7fa; border-color: rgba(0,0,0,0.1); }
|
||||
.app.light .tam-header-title { color: #1a237e; }
|
||||
.app.light .tam-header-ko { color: #546e7a; }
|
||||
.app.light .tam-close { color: #78909c; }
|
||||
.app.light .tam-close:hover { background: rgba(0,0,0,0.06); color: #37474f; }
|
||||
.app.light .tam-price-section { border-color: rgba(0,0,0,0.08); }
|
||||
.app.light .tam-market-name { color: #212121; }
|
||||
.app.light .tam-price-time { color: #78909c; }
|
||||
.app.light .tam-strategy-card { background: #f5f7fa; border-color: rgba(0,0,0,0.1); }
|
||||
.app.light .tam-strategy-label { color: #78909c; }
|
||||
.app.light .tam-strategy-val { color: #212121; }
|
||||
.app.light .tam-strategy-exec-val { color: #546e7a; }
|
||||
.app.light .tam-field-label { color: #546e7a; }
|
||||
.app.light .tam-pct-btn2 { background: #f0f3f8; border-color: rgba(0,0,0,0.12); color: #546e7a; }
|
||||
.app.light .tam-pct-btn2:hover { background: #e3eaf6; }
|
||||
.app.light .tam-price-input,
|
||||
.app.light .tam-memo-input { background: #f5f7fa; border-color: rgba(0,0,0,0.14); color: #212121; }
|
||||
.app.light .tam-market-btn { background: #f0f3f8; border-color: rgba(0,0,0,0.12); color: #546e7a; }
|
||||
.app.light .tam-market-btn:hover { background: #e3eaf6; color: #212121; }
|
||||
.app.light .tam-disclaimer { color: #90a4ae; }
|
||||
html.theme-light .tam-header { background: #f5f7fa; border-color: rgba(0,0,0,0.1); }
|
||||
html.theme-light .tam-header-title { color: #1a237e; }
|
||||
html.theme-light .tam-header-ko { color: #546e7a; }
|
||||
html.theme-light .tam-close { color: #78909c; }
|
||||
html.theme-light .tam-close:hover { background: rgba(0,0,0,0.06); color: #37474f; }
|
||||
html.theme-light .tam-price-section { border-color: rgba(0,0,0,0.08); }
|
||||
html.theme-light .tam-market-name { color: #212121; }
|
||||
html.theme-light .tam-price-time { color: #78909c; }
|
||||
html.theme-light .tam-strategy-card { background: #f5f7fa; border-color: rgba(0,0,0,0.1); }
|
||||
html.theme-light .tam-strategy-label { color: #78909c; }
|
||||
html.theme-light .tam-strategy-val { color: #212121; }
|
||||
html.theme-light .tam-strategy-exec-val { color: #546e7a; }
|
||||
html.theme-light .tam-field-label { color: #546e7a; }
|
||||
html.theme-light .tam-pct-btn2 { background: #f0f3f8; border-color: rgba(0,0,0,0.12); color: #546e7a; }
|
||||
html.theme-light .tam-pct-btn2:hover { background: #e3eaf6; }
|
||||
html.theme-light .tam-price-input,
|
||||
html.theme-light .tam-memo-input { background: #f5f7fa; border-color: rgba(0,0,0,0.14); color: #212121; }
|
||||
html.theme-light .tam-market-btn { background: #f0f3f8; border-color: rgba(0,0,0,0.12); color: #546e7a; }
|
||||
html.theme-light .tam-market-btn:hover { background: #e3eaf6; color: #212121; }
|
||||
html.theme-light .tam-disclaimer { color: #90a4ae; }
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════════════
|
||||
Trade signal notifications (tsn- / tnl- / tmb-notify-)
|
||||
|
||||
@@ -88,6 +88,7 @@ import LoginModal from './components/LoginModal';
|
||||
import SplashScreen from './components/SplashScreen';
|
||||
import { getAuthSession, setAuthSession, clearAuthSession, type AuthSession } from './utils/auth';
|
||||
import { isAppEntered, setAppEntered, clearAppEntered } from './utils/appEntry';
|
||||
import { syncDocumentTheme } from './utils/documentTheme';
|
||||
import { useMenuPermissions, invalidateMenuPermissionsCache } from './hooks/useMenuPermissions';
|
||||
import { firstAllowedTopMenu, normalizeRole } from './utils/permissions';
|
||||
import { clearAdminUnlock } from './utils/adminUnlock';
|
||||
@@ -991,6 +992,11 @@ function App() {
|
||||
saveState({ symbol, timeframe, chartType, theme, indicators, watchlist, alertPrices: alerts.map(a => a.price) });
|
||||
}, [symbol, timeframe, chartType, theme, indicators, watchlist, alerts]);
|
||||
|
||||
// body 포털(알림 팝업 등) 테마 CSS 변수 동기화
|
||||
useEffect(() => {
|
||||
syncDocumentTheme(theme);
|
||||
}, [theme]);
|
||||
|
||||
// ── DB 워크스페이스 동기화 ─────────────────────────────────────────────
|
||||
const workspaceState = useMemo(() => ({
|
||||
layoutId: layoutDef.id,
|
||||
@@ -1483,6 +1489,7 @@ function App() {
|
||||
|
||||
{menuPage === 'paper' && (
|
||||
<PaperTradingPage
|
||||
theme={theme}
|
||||
tickers={marketTickers}
|
||||
refreshKey={paperRefreshKey}
|
||||
defaultMarket={symbol}
|
||||
|
||||
@@ -17,6 +17,7 @@ import type { TradeOrderFillRequest } from '../types';
|
||||
import PaperMiniChart from './paper/PaperMiniChart';
|
||||
import PaperIndicatorPanel from './paper/PaperIndicatorPanel';
|
||||
import PaperCompactOrderbook from './paper/PaperCompactOrderbook';
|
||||
import type { Theme } from '../types';
|
||||
|
||||
const COIN_COLORS: Record<string, string> = {
|
||||
BTC: '#f7931a', ETH: '#627eea', XRP: '#23292f', SOL: '#9945ff',
|
||||
@@ -28,6 +29,7 @@ type HistoryTab = 'open' | 'recent';
|
||||
type RightTab = 'trade' | 'orderbook';
|
||||
|
||||
interface Props {
|
||||
theme?: Theme;
|
||||
tickers?: Map<string, { tradePrice: number | null }>;
|
||||
onGoChart?: (market: string) => void;
|
||||
refreshKey?: number;
|
||||
@@ -66,6 +68,7 @@ function coinIcon(code: string): string {
|
||||
}
|
||||
|
||||
const PaperTradingPage: React.FC<Props> = ({
|
||||
theme = 'dark',
|
||||
tickers,
|
||||
refreshKey = 0,
|
||||
defaultMarket = 'KRW-BTC',
|
||||
@@ -264,7 +267,7 @@ const PaperTradingPage: React.FC<Props> = ({
|
||||
|
||||
<main className="ptd-col ptd-col--center">
|
||||
<div className="ptd-card ptd-chart-card">
|
||||
<PaperMiniChart market={selectedMarket} />
|
||||
<PaperMiniChart market={selectedMarket} theme={theme} />
|
||||
<PaperIndicatorPanel market={selectedMarket} />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -93,8 +93,17 @@ export const TradeSignalSnackbar: React.FC<Props> = ({
|
||||
setPageIndex(p => Math.min(totalPages - 1, p + 1));
|
||||
}, [totalPages]);
|
||||
|
||||
const dismissAll = useCallback(() => {
|
||||
dismissAllToasts();
|
||||
setPageIndex(0);
|
||||
positionsRef.current = {};
|
||||
}, [dismissAllToasts]);
|
||||
|
||||
const dismissCurrentPage = useCallback(() => {
|
||||
dismissToasts(pageItems.map(i => i.id));
|
||||
positionsRef.current = Object.fromEntries(
|
||||
Object.entries(positionsRef.current).filter(([id]) => !pageItems.some(p => p.id === id)),
|
||||
);
|
||||
}, [dismissToasts, pageItems]);
|
||||
|
||||
const handleDragStart = useCallback((e: React.PointerEvent, key: string) => {
|
||||
@@ -219,7 +228,7 @@ export const TradeSignalSnackbar: React.FC<Props> = ({
|
||||
<button
|
||||
type="button"
|
||||
className="tsn-dismiss-all"
|
||||
onClick={dismissAllToasts}
|
||||
onClick={dismissAll}
|
||||
title={`대기 중인 알림 ${toastNotifications.length}건 전체 닫기`}
|
||||
>
|
||||
전체닫기 ({toastNotifications.length})
|
||||
|
||||
@@ -99,10 +99,10 @@ const BacktestAssetChart: React.FC<Props> = memo(({ curve, markers }) => {
|
||||
|
||||
{[0.25, 0.5, 0.75].map(r => {
|
||||
const y = pad.t + innerH * (1 - r);
|
||||
return <line key={r} x1={pad.l} y1={y} x2={W - pad.r} y2={y} stroke="rgba(201,162,39,0.07)" strokeWidth="1" />;
|
||||
return <line key={r} x1={pad.l} y1={y} x2={W - pad.r} y2={y} className="btd-chart-grid" />;
|
||||
})}
|
||||
|
||||
<text x={pad.l - 8} y={pad.t - 6} textAnchor="start" fill="#6272a4" fontSize="8">자본금</text>
|
||||
<text x={pad.l - 8} y={pad.t - 6} textAnchor="start" className="btd-chart-label" fontSize="8">자본금</text>
|
||||
|
||||
{chart.yTicks.map(v => (
|
||||
<text
|
||||
@@ -111,7 +111,7 @@ const BacktestAssetChart: React.FC<Props> = memo(({ curve, markers }) => {
|
||||
y={chart.toY(v)}
|
||||
textAnchor="end"
|
||||
dominantBaseline="middle"
|
||||
fill="#6272a4"
|
||||
className="btd-chart-label"
|
||||
fontSize="8.5"
|
||||
>
|
||||
{fmtY(v)}
|
||||
@@ -124,7 +124,7 @@ const BacktestAssetChart: React.FC<Props> = memo(({ curve, markers }) => {
|
||||
key={i}
|
||||
d={seg.d}
|
||||
fill="none"
|
||||
stroke={seg.up ? '#22c55e' : '#ef4444'}
|
||||
className={seg.up ? 'btd-chart-line-up' : 'btd-chart-line-down'}
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
@@ -152,7 +152,7 @@ const BacktestAssetChart: React.FC<Props> = memo(({ curve, markers }) => {
|
||||
))}
|
||||
|
||||
{chart.xLabels.map((l, i) => (
|
||||
<text key={i} x={l.x} y={H - 5} textAnchor="middle" fill="#6272a4" fontSize="8">
|
||||
<text key={i} x={l.x} y={H - 5} textAnchor="middle" className="btd-chart-label" fontSize="8">
|
||||
{l.label}
|
||||
</text>
|
||||
))}
|
||||
|
||||
@@ -1,44 +1,84 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { createChart, CandlestickSeries, type IChartApi, type ISeriesApi, type Time, ColorType } from 'lightweight-charts';
|
||||
import type { Timeframe } from '../../types';
|
||||
import type { Theme, Timeframe } from '../../types';
|
||||
import { fetchUpbitCandles } from '../../utils/upbitApi';
|
||||
|
||||
const TF_OPTIONS: Timeframe[] = ['1m', '5m', '15m', '1h', '4h', '1D'];
|
||||
|
||||
interface Props {
|
||||
market: string;
|
||||
theme?: Theme;
|
||||
wsLabel?: string;
|
||||
}
|
||||
|
||||
const PaperMiniChart: React.FC<Props> = ({ market, wsLabel = 'WebSocket <100ms' }) => {
|
||||
function readChartTheme(container: HTMLElement | null) {
|
||||
const root = container?.closest('.app') ?? document.documentElement;
|
||||
const s = getComputedStyle(root);
|
||||
const v = (name: string, fallback: string) => s.getPropertyValue(name).trim() || fallback;
|
||||
return {
|
||||
bgColor: v('--bg3', '#1f2335'),
|
||||
textColor: v('--text', '#c0caf5'),
|
||||
gridColor: v('--sep', 'rgba(122, 162, 247, 0.15)'),
|
||||
borderColor: v('--border', 'rgba(122, 162, 247, 0.15)'),
|
||||
upColor: v('--up', '#ff6b6b'),
|
||||
downColor: v('--down', '#4dabf7'),
|
||||
};
|
||||
}
|
||||
|
||||
const PaperMiniChart: React.FC<Props> = ({ market, theme = 'dark', wsLabel = 'WebSocket <100ms' }) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const chartRef = useRef<IChartApi | null>(null);
|
||||
const seriesRef = useRef<ISeriesApi<'Candlestick'> | null>(null);
|
||||
const [timeframe, setTimeframe] = useState<Timeframe>('1h');
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return undefined;
|
||||
const chart = createChart(containerRef.current, {
|
||||
const applyTheme = useCallback((chart: IChartApi, series: ISeriesApi<'Candlestick'>) => {
|
||||
const t = readChartTheme(containerRef.current);
|
||||
chart.applyOptions({
|
||||
layout: {
|
||||
background: { type: ColorType.Solid, color: '#121520' },
|
||||
textColor: '#9aa5ce',
|
||||
background: { type: ColorType.Solid, color: t.bgColor },
|
||||
textColor: t.textColor,
|
||||
},
|
||||
grid: {
|
||||
vertLines: { color: 'rgba(122,162,247,0.06)' },
|
||||
horzLines: { color: 'rgba(122,162,247,0.06)' },
|
||||
vertLines: { color: t.gridColor },
|
||||
horzLines: { color: t.gridColor },
|
||||
},
|
||||
rightPriceScale: { borderColor: 'rgba(122,162,247,0.12)' },
|
||||
timeScale: { borderColor: 'rgba(122,162,247,0.12)' },
|
||||
rightPriceScale: { borderColor: t.borderColor },
|
||||
timeScale: { borderColor: t.borderColor },
|
||||
});
|
||||
series.applyOptions({
|
||||
upColor: t.upColor,
|
||||
downColor: t.downColor,
|
||||
borderUpColor: t.upColor,
|
||||
borderDownColor: t.downColor,
|
||||
wickUpColor: t.upColor,
|
||||
wickDownColor: t.downColor,
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return undefined;
|
||||
const t = readChartTheme(containerRef.current);
|
||||
const chart = createChart(containerRef.current, {
|
||||
layout: {
|
||||
background: { type: ColorType.Solid, color: t.bgColor },
|
||||
textColor: t.textColor,
|
||||
},
|
||||
grid: {
|
||||
vertLines: { color: t.gridColor },
|
||||
horzLines: { color: t.gridColor },
|
||||
},
|
||||
rightPriceScale: { borderColor: t.borderColor },
|
||||
timeScale: { borderColor: t.borderColor },
|
||||
crosshair: { mode: 1 },
|
||||
});
|
||||
const series = chart.addSeries(CandlestickSeries, {
|
||||
upColor: '#22c55e',
|
||||
downColor: '#ef4444',
|
||||
borderUpColor: '#22c55e',
|
||||
borderDownColor: '#ef4444',
|
||||
wickUpColor: '#22c55e',
|
||||
wickDownColor: '#ef4444',
|
||||
upColor: t.upColor,
|
||||
downColor: t.downColor,
|
||||
borderUpColor: t.upColor,
|
||||
borderDownColor: t.downColor,
|
||||
wickUpColor: t.upColor,
|
||||
wickDownColor: t.downColor,
|
||||
});
|
||||
chartRef.current = chart;
|
||||
seriesRef.current = series;
|
||||
@@ -61,6 +101,12 @@ const PaperMiniChart: React.FC<Props> = ({ market, wsLabel = 'WebSocket <100ms'
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (chartRef.current && seriesRef.current) {
|
||||
applyTheme(chartRef.current, seriesRef.current);
|
||||
}
|
||||
}, [theme, applyTheme]);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
setLoading(true);
|
||||
|
||||
@@ -10,6 +10,7 @@ import React, {
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import type { TradeSignalInfo } from '../components/TradeAlertModal';
|
||||
@@ -121,6 +122,8 @@ export const TradeNotificationProvider: React.FC<ProviderProps> = ({
|
||||
const alertSoundId = normalizeTradeAlertSoundId(soundId) as TradeAlertSoundId;
|
||||
const [readIds, setReadIds] = useState<Set<string>>(() => loadReadIds());
|
||||
const [toastNotifications, setToastNotifications] = useState<TradeNotificationItem[]>([]);
|
||||
const toastNotificationsRef = useRef(toastNotifications);
|
||||
toastNotificationsRef.current = toastNotifications;
|
||||
const [allNotifications, setAllNotifications] = useState<TradeNotificationItem[]>([]);
|
||||
const [detailSignal, setDetailSignal] = useState<TradeSignalInfo | null>(null);
|
||||
const [detailCentered, setDetailCentered] = useState(false);
|
||||
@@ -247,20 +250,10 @@ export const TradeNotificationProvider: React.FC<ProviderProps> = ({
|
||||
}, []);
|
||||
|
||||
const dismissAllToasts = useCallback(() => {
|
||||
setToastNotifications(prev => {
|
||||
const ids = prev.map(n => n.id);
|
||||
setReadIds(r => {
|
||||
const next = new Set(r);
|
||||
ids.forEach(i => next.add(i));
|
||||
saveReadIds(next);
|
||||
return next;
|
||||
});
|
||||
setAllNotifications(all =>
|
||||
all.map(n => (ids.includes(n.id) ? { ...n, isRead: true } : n)),
|
||||
);
|
||||
return [];
|
||||
});
|
||||
}, []);
|
||||
const ids = toastNotificationsRef.current.map(n => n.id);
|
||||
if (ids.length === 0) return;
|
||||
dismissToasts(ids);
|
||||
}, [dismissToasts]);
|
||||
|
||||
const markAllAsRead = useCallback(() => {
|
||||
setAllNotifications(prev => {
|
||||
|
||||
@@ -287,28 +287,44 @@
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
/* 라이트 테마 */
|
||||
/* 라이트 테마 — body 포털(html.theme-light) · 앱 내부(.app.light) 공통 */
|
||||
html.theme-light .app-popup-shell,
|
||||
.app.light .app-popup-shell,
|
||||
html.theme-light .tam-modal,
|
||||
.app.light .tam-modal,
|
||||
html.theme-light .lsp-modal,
|
||||
.app.light .lsp-modal,
|
||||
html.theme-light .gc-popup-panel,
|
||||
.app.light .gc-popup-panel,
|
||||
html.theme-light .bts-modal,
|
||||
.app.light .bts-modal,
|
||||
html.theme-light .brm-modal,
|
||||
.app.light .brm-modal,
|
||||
html.theme-light .ism-dialog,
|
||||
.app.light .ism-dialog,
|
||||
html.theme-light .login-modal,
|
||||
.app.light .login-modal {
|
||||
background: #ffffff;
|
||||
border-color: rgba(25, 118, 210, 0.35);
|
||||
color: #212121;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.18), 0 0 40px rgba(25, 118, 210, 0.08);
|
||||
}
|
||||
html.theme-light .app-popup-header,
|
||||
.app.light .app-popup-header,
|
||||
html.theme-light .gc-popup-header,
|
||||
.app.light .gc-popup-header {
|
||||
background: linear-gradient(180deg, rgba(25, 118, 210, 0.1) 0%, #f5f7fa 100%);
|
||||
border-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
html.theme-light .app-popup-header-title,
|
||||
.app.light .app-popup-header-title,
|
||||
html.theme-light .gc-popup-title,
|
||||
.app.light .gc-popup-title { color: #1a237e; }
|
||||
html.theme-light .app-popup-header-ko,
|
||||
.app.light .app-popup-header-ko { color: #546e7a; }
|
||||
html.theme-light .app-popup-card,
|
||||
.app.light .app-popup-card { background: #f5f7fa; border-color: rgba(0, 0, 0, 0.1); }
|
||||
html.theme-light .app-popup-input,
|
||||
.app.light .app-popup-input,
|
||||
html.theme-light .app-popup-select,
|
||||
.app.light .app-popup-select { background: #f0f3f8; border-color: rgba(0, 0, 0, 0.12); color: #212121; }
|
||||
|
||||
@@ -1,14 +1,30 @@
|
||||
/* 백테스팅 대시보드 (btd-*) — 금색 포인트 다크 테마 */
|
||||
/* 백테스팅 대시보드 (btd-*) — 앱 테마 변수 + 금색 포인트 */
|
||||
|
||||
.btd-page {
|
||||
--btd-gold: #c9a227;
|
||||
--btd-gold-light: #e8c547;
|
||||
--btd-gold-dark: #b8860b;
|
||||
--btd-gold-border: rgba(201, 162, 39, 0.18);
|
||||
--btd-gold-border-strong: rgba(201, 162, 39, 0.35);
|
||||
--btd-gold-bg: rgba(201, 162, 39, 0.08);
|
||||
--btd-gold-bg-hover: rgba(201, 162, 39, 0.14);
|
||||
|
||||
display: flex;
|
||||
height: calc(100vh - var(--tmb-h, 46px));
|
||||
overflow: hidden;
|
||||
background: #0a0e14;
|
||||
color: #c8d0e0;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font-family: var(--font, 'Noto Sans KR', sans-serif);
|
||||
}
|
||||
|
||||
.app.light .btd-page,
|
||||
html.theme-light .btd-page {
|
||||
--btd-gold-border: rgba(184, 134, 11, 0.28);
|
||||
--btd-gold-border-strong: rgba(184, 134, 11, 0.45);
|
||||
--btd-gold-bg: rgba(201, 162, 39, 0.1);
|
||||
--btd-gold-bg-hover: rgba(201, 162, 39, 0.16);
|
||||
}
|
||||
|
||||
/* ── 좌측 타임라인 사이드바 (~23%) ── */
|
||||
.btd-sidebar {
|
||||
width: 23%;
|
||||
@@ -17,8 +33,8 @@
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-right: 1px solid rgba(201, 162, 39, 0.15);
|
||||
background: #0d1219;
|
||||
border-right: 1px solid var(--btd-gold-border);
|
||||
background: var(--bg2);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -27,7 +43,7 @@
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 12px 10px;
|
||||
border-bottom: 1px solid rgba(201, 162, 39, 0.12);
|
||||
border-bottom: 1px solid var(--btd-gold-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -35,7 +51,7 @@
|
||||
width: 3px;
|
||||
height: 18px;
|
||||
border-radius: 2px;
|
||||
background: linear-gradient(180deg, #e8c547, #b8860b);
|
||||
background: linear-gradient(180deg, var(--btd-gold-light), var(--btd-gold-dark));
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -44,7 +60,7 @@
|
||||
flex: 1;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
color: #f0e6c8;
|
||||
color: var(--text);
|
||||
letter-spacing: -0.2px;
|
||||
}
|
||||
|
||||
@@ -57,16 +73,16 @@
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid rgba(201, 162, 39, 0.2);
|
||||
background: rgba(201, 162, 39, 0.06);
|
||||
color: #c9a227;
|
||||
border: 1px solid var(--btd-gold-border);
|
||||
background: var(--btd-gold-bg);
|
||||
color: var(--btd-gold);
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.btd-icon-btn:hover:not(:disabled) { background: rgba(201, 162, 39, 0.14); }
|
||||
.btd-icon-btn:hover:not(:disabled) { background: var(--btd-gold-bg-hover); }
|
||||
.btd-icon-btn:disabled { opacity: 0.35; cursor: not-allowed; }
|
||||
.btd-icon-btn--danger { color: #ef4444; border-color: rgba(239, 68, 68, 0.3); }
|
||||
|
||||
@@ -78,7 +94,7 @@
|
||||
justify-content: center;
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
color: #6272a4;
|
||||
color: var(--text3);
|
||||
font-size: 12px;
|
||||
gap: 8px;
|
||||
}
|
||||
@@ -121,32 +137,32 @@
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
background: #1a2030;
|
||||
background: var(--bg3);
|
||||
border: 2px solid rgba(201, 162, 39, 0.45);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.btd-timeline-item--active .btd-timeline-node {
|
||||
background: #c9a227;
|
||||
border-color: #e8c547;
|
||||
background: var(--btd-gold);
|
||||
border-color: var(--btd-gold-light);
|
||||
box-shadow: 0 0 8px rgba(201, 162, 39, 0.5);
|
||||
}
|
||||
|
||||
.btd-timeline-card {
|
||||
background: #121820;
|
||||
border: 1px solid rgba(201, 162, 39, 0.12);
|
||||
background: var(--bg3);
|
||||
border: 1px solid var(--btd-gold-border);
|
||||
border-radius: 8px;
|
||||
padding: 8px 10px;
|
||||
transition: border-color 0.15s, box-shadow 0.15s;
|
||||
}
|
||||
|
||||
.btd-timeline-item:hover .btd-timeline-card {
|
||||
border-color: rgba(201, 162, 39, 0.28);
|
||||
border-color: var(--btd-gold-border-strong);
|
||||
}
|
||||
|
||||
.btd-timeline-item--active .btd-timeline-card {
|
||||
border-color: rgba(201, 162, 39, 0.65);
|
||||
box-shadow: 0 0 0 1px rgba(201, 162, 39, 0.2), 0 4px 16px rgba(0, 0, 0, 0.35);
|
||||
box-shadow: 0 0 0 1px rgba(201, 162, 39, 0.2), 0 4px 16px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.btd-timeline-top {
|
||||
@@ -160,7 +176,7 @@
|
||||
.btd-timeline-name {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #eef2ff;
|
||||
color: var(--text);
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
@@ -169,7 +185,7 @@
|
||||
.btd-timeline-date {
|
||||
display: block;
|
||||
font-size: 10px;
|
||||
color: #6272a4;
|
||||
color: var(--text3);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
@@ -199,7 +215,7 @@
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #0a0e14;
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
.btd-dashboard {
|
||||
@@ -219,7 +235,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
color: #6272a4;
|
||||
color: var(--text3);
|
||||
font-size: 13px;
|
||||
}
|
||||
.btd-empty span { font-size: 48px; opacity: 0.35; }
|
||||
@@ -237,7 +253,7 @@
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
border-radius: 2px;
|
||||
background: linear-gradient(180deg, #e8c547, #b8860b);
|
||||
background: linear-gradient(180deg, var(--btd-gold-light), var(--btd-gold-dark));
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -245,7 +261,7 @@
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
color: #f0e6c8;
|
||||
color: var(--text);
|
||||
letter-spacing: -0.2px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
@@ -253,11 +269,10 @@
|
||||
.btd-section-sub {
|
||||
margin: 1px 0 0;
|
||||
font-size: 9px;
|
||||
color: #6272a4;
|
||||
color: var(--text3);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* KPI ~18% | 차트 ~44% | 테이블 ~32% (헤더 포함) */
|
||||
.btd-section--kpi {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
@@ -286,8 +301,8 @@
|
||||
}
|
||||
|
||||
.btd-kpi-card {
|
||||
background: #121820;
|
||||
border: 1px solid rgba(201, 162, 39, 0.18);
|
||||
background: var(--bg2);
|
||||
border: 1px solid var(--btd-gold-border);
|
||||
border-radius: 10px;
|
||||
padding: 10px 14px;
|
||||
min-height: 0;
|
||||
@@ -295,7 +310,7 @@
|
||||
|
||||
.btd-kpi-label {
|
||||
font-size: 10px;
|
||||
color: #9aa5ce;
|
||||
color: var(--text2);
|
||||
margin-bottom: 4px;
|
||||
font-weight: 600;
|
||||
}
|
||||
@@ -303,19 +318,19 @@
|
||||
.btd-kpi-value {
|
||||
font-size: 24px;
|
||||
font-weight: 900;
|
||||
color: #fff;
|
||||
color: var(--text);
|
||||
line-height: 1;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
.btd-kpi-value.up { color: #22c55e; }
|
||||
.btd-kpi-value.down { color: #ef4444; }
|
||||
.btd-kpi-value.gold { color: #c9a227; }
|
||||
.btd-kpi-value.neutral { color: #e2e8f0; }
|
||||
.btd-kpi-value.gold { color: var(--btd-gold); }
|
||||
.btd-kpi-value.neutral { color: var(--text2); }
|
||||
|
||||
.btd-kpi-desc {
|
||||
margin: 6px 0 0;
|
||||
font-size: 9px;
|
||||
color: #6272a4;
|
||||
color: var(--text3);
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
@@ -329,7 +344,7 @@
|
||||
.btd-kpi-icon {
|
||||
font-size: 20px;
|
||||
opacity: 0.6;
|
||||
color: #c9a227;
|
||||
color: var(--btd-gold);
|
||||
}
|
||||
|
||||
.btd-kpi-dual {
|
||||
@@ -352,8 +367,8 @@
|
||||
.btd-chart-card {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
background: #121820;
|
||||
border: 1px solid rgba(201, 162, 39, 0.18);
|
||||
background: var(--bg2);
|
||||
border: 1px solid var(--btd-gold-border);
|
||||
border-radius: 10px;
|
||||
padding: 4px 8px 2px;
|
||||
display: flex;
|
||||
@@ -373,12 +388,24 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
.btd-chart-grid {
|
||||
stroke: var(--sep);
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
.btd-chart-label {
|
||||
fill: var(--text3);
|
||||
}
|
||||
|
||||
.btd-chart-line-up { stroke: #22c55e; }
|
||||
.btd-chart-line-down { stroke: #ef4444; }
|
||||
|
||||
/* ── 거래 내역 테이블 ── */
|
||||
.btd-table-card {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
background: #121820;
|
||||
border: 1px solid rgba(201, 162, 39, 0.18);
|
||||
background: var(--bg2);
|
||||
border: 1px solid var(--btd-gold-border);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
@@ -399,7 +426,7 @@
|
||||
}
|
||||
|
||||
.btd-table thead {
|
||||
background: rgba(201, 162, 39, 0.1);
|
||||
background: var(--btd-gold-bg);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
@@ -410,19 +437,19 @@
|
||||
text-align: left;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
color: #c9a227;
|
||||
border-bottom: 1px solid rgba(201, 162, 39, 0.2);
|
||||
color: var(--btd-gold);
|
||||
border-bottom: 1px solid var(--btd-gold-border);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.btd-table td {
|
||||
padding: 7px 12px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
||||
color: #c8d0e0;
|
||||
border-bottom: 1px solid var(--sep);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.btd-table tbody tr:hover td {
|
||||
background: rgba(201, 162, 39, 0.04);
|
||||
background: var(--btd-gold-bg);
|
||||
}
|
||||
|
||||
.btd-table tbody tr:last-child td {
|
||||
@@ -430,19 +457,19 @@
|
||||
}
|
||||
|
||||
.btd-td-time {
|
||||
color: #6272a4;
|
||||
color: var(--text3);
|
||||
font-variant-numeric: tabular-nums;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.btd-table td.buy { color: #3b82f6; font-weight: 700; }
|
||||
.btd-table td.sell { color: #ef4444; font-weight: 700; }
|
||||
.btd-table td.buy { color: var(--down, #3b82f6); font-weight: 700; }
|
||||
.btd-table td.sell { color: var(--up, #ef4444); font-weight: 700; }
|
||||
.btd-table td.up { color: #22c55e; font-weight: 700; }
|
||||
.btd-table td.down { color: #ef4444; font-weight: 700; }
|
||||
|
||||
.btd-table-empty {
|
||||
text-align: center;
|
||||
color: #6272a4;
|
||||
color: var(--text3);
|
||||
padding: 24px !important;
|
||||
}
|
||||
|
||||
@@ -452,6 +479,11 @@
|
||||
|
||||
@media (max-width: 860px) {
|
||||
.btd-page { flex-direction: column; height: auto; overflow: auto; }
|
||||
.btd-sidebar { width: 100%; max-height: 240px; border-right: none; border-bottom: 1px solid rgba(201, 162, 39, 0.15); }
|
||||
.btd-sidebar {
|
||||
width: 100%;
|
||||
max-height: 240px;
|
||||
border-right: none;
|
||||
border-bottom: 1px solid var(--btd-gold-border);
|
||||
}
|
||||
.btd-kpi-grid { grid-template-columns: 1fr 1fr; }
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* 모의투자 대시보드 (ptd-) — 전체 화면 고정 레이아웃 */
|
||||
/* 모의투자 대시보드 (ptd-) — 전체 화면 고정 레이아웃, 앱 테마 변수 연동 */
|
||||
.ptd-page {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #0d1117;
|
||||
color: #c0caf5;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
padding: 8px 12px 10px;
|
||||
font-family: var(--font, 'Noto Sans KR', sans-serif);
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 320px;
|
||||
color: #9aa5ce;
|
||||
color: var(--text2);
|
||||
}
|
||||
|
||||
.ptd-topbar {
|
||||
@@ -26,18 +26,18 @@
|
||||
margin-bottom: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ptd-title { margin: 0; font-size: 18px; font-weight: 800; color: #fff; }
|
||||
.ptd-title { margin: 0; font-size: 18px; font-weight: 800; color: var(--text); }
|
||||
.ptd-topbar-actions { display: flex; gap: 8px; flex-shrink: 0; }
|
||||
.ptd-btn {
|
||||
padding: 6px 10px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(122,162,247,0.2);
|
||||
background: #1e222d;
|
||||
color: #c0caf5;
|
||||
border: 1px solid var(--border);
|
||||
background: var(--bg2);
|
||||
color: var(--text);
|
||||
font-size: 11px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ptd-btn:hover { background: #252a38; }
|
||||
.ptd-btn:hover { background: var(--bg3); }
|
||||
.ptd-btn--danger { border-color: rgba(239,68,68,0.4); color: #ef4444; }
|
||||
|
||||
.ptd-banner {
|
||||
@@ -68,13 +68,13 @@
|
||||
gap: 8px;
|
||||
padding: 8px 10px;
|
||||
border-radius: 10px;
|
||||
background: #1e222d;
|
||||
border: 1px solid rgba(122,162,247,0.12);
|
||||
background: var(--bg2);
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
.ptd-metric-icon { font-size: 16px; line-height: 1; }
|
||||
.ptd-metric-title { font-size: 10px; color: #6272a4; margin-bottom: 2px; }
|
||||
.ptd-metric-value { font-size: 17px; font-weight: 800; line-height: 1.1; }
|
||||
.ptd-metric-sub { font-size: 9px; color: #6272a4; margin-top: 2px; }
|
||||
.ptd-metric-title { font-size: 10px; color: var(--text3); margin-bottom: 2px; }
|
||||
.ptd-metric-value { font-size: 17px; font-weight: 800; line-height: 1.1; color: var(--text); }
|
||||
.ptd-metric-sub { font-size: 9px; color: var(--text3); margin-top: 2px; }
|
||||
.ptd-metric--up .ptd-metric-value { color: #22c55e; }
|
||||
.ptd-metric--down .ptd-metric-value { color: #ef4444; }
|
||||
|
||||
@@ -101,8 +101,8 @@
|
||||
.ptd-col--right { min-width: 0; }
|
||||
|
||||
.ptd-card {
|
||||
background: #1e222d;
|
||||
border: 1px solid rgba(122,162,247,0.12);
|
||||
background: var(--bg2);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
@@ -111,22 +111,22 @@
|
||||
padding: 8px 10px 0;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
color: #9aa5ce;
|
||||
color: var(--text2);
|
||||
}
|
||||
.ptd-asset-card { padding-bottom: 8px; }
|
||||
.ptd-asset-total {
|
||||
padding: 4px 10px 0;
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
color: #fff;
|
||||
color: var(--text);
|
||||
}
|
||||
.ptd-asset-total span { font-size: 12px; color: #6272a4; font-weight: 600; }
|
||||
.ptd-asset-total span { font-size: 12px; color: var(--text3); font-weight: 600; }
|
||||
.ptd-asset-ret {
|
||||
padding: 2px 10px 0;
|
||||
font-size: 18px;
|
||||
font-weight: 800;
|
||||
}
|
||||
.ptd-asset-sub { padding: 4px 10px 0; font-size: 10px; color: #6272a4; }
|
||||
.ptd-asset-sub { padding: 4px 10px 0; font-size: 10px; color: var(--text3); }
|
||||
|
||||
.ptd-table {
|
||||
width: 100%;
|
||||
@@ -136,12 +136,12 @@
|
||||
.ptd-table th, .ptd-table td {
|
||||
padding: 6px 8px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid rgba(122,162,247,0.08);
|
||||
border-bottom: 1px solid var(--sep);
|
||||
}
|
||||
.ptd-table th { color: #6272a4; font-weight: 600; }
|
||||
.ptd-table th { color: var(--text3); font-weight: 600; }
|
||||
.ptd-table tbody tr { cursor: pointer; }
|
||||
.ptd-table tbody tr:hover { background: rgba(63,126,245,0.06); }
|
||||
.ptd-row--sel { background: rgba(63,126,245,0.1); }
|
||||
.ptd-table tbody tr:hover { background: var(--bg3); }
|
||||
.ptd-row--sel { background: var(--bg3); }
|
||||
.ptd-coin {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -154,8 +154,8 @@
|
||||
color: #fff;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.ptd-muted { color: #6272a4; text-align: center; padding: 12px; font-size: 11px; }
|
||||
.ptd-time { color: #6272a4; white-space: nowrap; }
|
||||
.ptd-muted { color: var(--text3); text-align: center; padding: 12px; font-size: 11px; }
|
||||
.ptd-time { color: var(--text3); white-space: nowrap; }
|
||||
|
||||
.ptd-donut-card { padding-bottom: 8px; }
|
||||
.ptd-donut-wrap {
|
||||
@@ -175,20 +175,20 @@
|
||||
height: 44px;
|
||||
margin: 14px auto;
|
||||
border-radius: 50%;
|
||||
background: #1e222d;
|
||||
background: var(--bg2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
color: #c0caf5;
|
||||
color: var(--text);
|
||||
}
|
||||
.ptd-donut-legend {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 10px;
|
||||
color: #9aa5ce;
|
||||
color: var(--text2);
|
||||
}
|
||||
.ptd-donut-legend li { display: flex; align-items: center; gap: 6px; margin-bottom: 3px; }
|
||||
.ptd-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
|
||||
@@ -215,7 +215,7 @@
|
||||
margin-bottom: 6px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ptd-chart-title { font-size: 12px; font-weight: 700; }
|
||||
.ptd-chart-title { font-size: 12px; font-weight: 700; color: var(--text); }
|
||||
.ptd-ws-badge {
|
||||
font-size: 9px;
|
||||
padding: 2px 6px;
|
||||
@@ -235,7 +235,7 @@
|
||||
inset: 40% 0 auto;
|
||||
text-align: center;
|
||||
font-size: 11px;
|
||||
color: #6272a4;
|
||||
color: var(--text3);
|
||||
pointer-events: none;
|
||||
}
|
||||
.ptd-tf-row {
|
||||
@@ -248,16 +248,16 @@
|
||||
.ptd-tf-btn {
|
||||
padding: 3px 7px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid rgba(122,162,247,0.15);
|
||||
background: #121520;
|
||||
color: #9aa5ce;
|
||||
border: 1px solid var(--border);
|
||||
background: var(--bg3);
|
||||
color: var(--text2);
|
||||
font-size: 9px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ptd-tf-btn--active {
|
||||
border-color: #3f7ef5;
|
||||
color: #3f7ef5;
|
||||
background: rgba(63,126,245,0.12);
|
||||
border-color: var(--accent);
|
||||
color: var(--accent);
|
||||
background: var(--bg2);
|
||||
}
|
||||
|
||||
.ptd-indicators {
|
||||
@@ -265,16 +265,16 @@
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 6px;
|
||||
padding: 0 10px 8px;
|
||||
border-top: 1px solid rgba(122,162,247,0.08);
|
||||
border-top: 1px solid var(--sep);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ptd-ind-panel {
|
||||
background: #121520;
|
||||
background: var(--bg3);
|
||||
border-radius: 8px;
|
||||
padding: 4px 6px;
|
||||
min-height: 52px;
|
||||
}
|
||||
.ptd-ind-label { font-size: 9px; color: #6272a4; margin-bottom: 2px; }
|
||||
.ptd-ind-label { font-size: 9px; color: var(--text3); margin-bottom: 2px; }
|
||||
.ptd-ind-svg { width: 100%; height: 36px; display: block; }
|
||||
|
||||
/* 우측 패널 — 매매/호가 탭 */
|
||||
@@ -283,14 +283,14 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
background: #1e222d;
|
||||
border: 1px solid rgba(122,162,247,0.12);
|
||||
background: var(--bg2);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ptd-tabs--main {
|
||||
flex-shrink: 0;
|
||||
background: #121520;
|
||||
background: var(--bg3);
|
||||
}
|
||||
.ptd-tabs--main .ptd-tab {
|
||||
padding: 10px;
|
||||
@@ -320,11 +320,11 @@
|
||||
.ptd-order-card .top-panel { padding: 4px 2px; background: transparent; }
|
||||
.ptd-order-card .top-field { margin-bottom: 4px; }
|
||||
.ptd-order-card .top-submit--buy { background: #22c55e !important; border-color: #22c55e !important; }
|
||||
.ptd-order-card .top-submit--sell { background: #3f7ef5 !important; border-color: #3f7ef5 !important; }
|
||||
.ptd-order-card .top-submit--sell { background: var(--accent) !important; border-color: var(--accent) !important; }
|
||||
|
||||
.ptd-ob {
|
||||
background: #1e222d;
|
||||
border: 1px solid rgba(122,162,247,0.12);
|
||||
background: var(--bg2);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -339,8 +339,8 @@
|
||||
padding: 8px 10px;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
color: #9aa5ce;
|
||||
border-bottom: 1px solid rgba(122,162,247,0.08);
|
||||
color: var(--text2);
|
||||
border-bottom: 1px solid var(--sep);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ptd-ob-body {
|
||||
@@ -378,15 +378,15 @@
|
||||
.ptd-ob-row--bid .ptd-ob-bar { background: #22c55e; left: 0; right: auto; }
|
||||
.ptd-ob-row--ask .ptd-ob-price { color: #ef4444; position: relative; z-index: 1; }
|
||||
.ptd-ob-row--bid .ptd-ob-price { color: #22c55e; position: relative; z-index: 1; }
|
||||
.ptd-ob-size { position: relative; z-index: 1; color: #6272a4; }
|
||||
.ptd-ob-size { position: relative; z-index: 1; color: var(--text3); }
|
||||
.ptd-ob-mid {
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
color: #fff;
|
||||
border-top: 1px solid rgba(122,162,247,0.08);
|
||||
border-bottom: 1px solid rgba(122,162,247,0.08);
|
||||
color: var(--text);
|
||||
border-top: 1px solid var(--sep);
|
||||
border-bottom: 1px solid var(--sep);
|
||||
}
|
||||
|
||||
.ptd-history-card {
|
||||
@@ -402,17 +402,17 @@
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.ptd-tabs { display: flex; border-bottom: 1px solid rgba(122,162,247,0.1); flex-shrink: 0; }
|
||||
.ptd-tabs { display: flex; border-bottom: 1px solid var(--sep); flex-shrink: 0; }
|
||||
.ptd-tab {
|
||||
flex: 1;
|
||||
padding: 7px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #6272a4;
|
||||
color: var(--text3);
|
||||
font-size: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ptd-tab.active { color: #3f7ef5; font-weight: 700; border-bottom: 2px solid #3f7ef5; }
|
||||
.ptd-tab.active { color: var(--accent); font-weight: 700; border-bottom: 2px solid var(--accent); }
|
||||
.ptd-table--compact { font-size: 9px; }
|
||||
.ptd-table--compact th,
|
||||
.ptd-table--compact td { padding: 5px 6px; }
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { Theme } from '../types';
|
||||
|
||||
const HTML_THEME_CLASSES = ['theme-dark', 'theme-light', 'theme-blue'] as const;
|
||||
|
||||
/** body 포털(알림 팝업 등)에서도 테마 CSS 변수가 적용되도록 html 클래스 동기화 */
|
||||
export function syncDocumentTheme(theme: Theme): void {
|
||||
if (typeof document === 'undefined') return;
|
||||
const html = document.documentElement;
|
||||
html.classList.remove(...HTML_THEME_CLASSES);
|
||||
html.classList.add(`theme-${theme}`);
|
||||
}
|
||||
Reference in New Issue
Block a user