import type { DashboardChartTimeframe } from "@/features/trade/types/trade.types"; import type { ChartBar } from "./chart-utils"; export const UP_COLOR = "#ef4444"; export const MINUTE_SYNC_INTERVAL_MS = 30000; export const REALTIME_STALE_THRESHOLD_MS = 12000; export const CHART_MIN_HEIGHT = 220; export interface ChartPalette { backgroundColor: string; downColor: string; volumeDownColor: string; textColor: string; borderColor: string; gridColor: string; crosshairColor: string; } export const DEFAULT_CHART_PALETTE: ChartPalette = { backgroundColor: "#ffffff", downColor: "#2563eb", volumeDownColor: "rgba(37, 99, 235, 0.45)", textColor: "#6d28d9", borderColor: "#e9d5ff", gridColor: "#f3e8ff", crosshairColor: "#c084fc", }; export const MINUTE_TIMEFRAMES: Array<{ value: DashboardChartTimeframe; label: string; }> = [ { value: "1m", label: "1분" }, { value: "30m", label: "30분" }, { value: "1h", label: "1시간" }, ]; export const PERIOD_TIMEFRAMES: Array<{ value: DashboardChartTimeframe; label: string; }> = [ { value: "1d", label: "일" }, { value: "1w", label: "주" }, ]; /** * @description 브랜드 CSS 변수에서 차트 팔레트를 읽어옵니다. * @see features/trade/components/chart/StockLineChart.tsx 차트 생성/테마 반영 */ export function getChartPaletteFromCssVars( themeMode: "light" | "dark", ): ChartPalette { const isDark = themeMode === "dark"; const backgroundVar = isDark ? "--brand-chart-background-dark" : "--brand-chart-background-light"; const textVar = isDark ? "--brand-chart-text-dark" : "--brand-chart-text-light"; const borderVar = isDark ? "--brand-chart-border-dark" : "--brand-chart-border-light"; const gridVar = isDark ? "--brand-chart-grid-dark" : "--brand-chart-grid-light"; const crosshairVar = isDark ? "--brand-chart-crosshair-dark" : "--brand-chart-crosshair-light"; return { backgroundColor: readCssVar( backgroundVar, DEFAULT_CHART_PALETTE.backgroundColor, ), downColor: readCssVar( "--brand-chart-down", DEFAULT_CHART_PALETTE.downColor, ), volumeDownColor: readCssVar( "--brand-chart-volume-down", DEFAULT_CHART_PALETTE.volumeDownColor, ), textColor: readCssVar(textVar, DEFAULT_CHART_PALETTE.textColor), borderColor: readCssVar(borderVar, DEFAULT_CHART_PALETTE.borderColor), gridColor: readCssVar(gridVar, DEFAULT_CHART_PALETTE.gridColor), crosshairColor: readCssVar( crosshairVar, DEFAULT_CHART_PALETTE.crosshairColor, ), }; } /** * @description 차트 데이터 배열이 동일한지 비교합니다. * @see features/trade/components/chart/StockLineChart.tsx 분봉 동기화 시 불필요한 상태 업데이트 방지 */ export function areBarsEqual(left: ChartBar[], right: ChartBar[]) { if (left.length !== right.length) return false; for (let index = 0; index < left.length; index += 1) { const lhs = left[index]; const rhs = right[index]; if (!lhs || !rhs) return false; if ( lhs.time !== rhs.time || lhs.open !== rhs.open || lhs.high !== rhs.high || lhs.low !== rhs.low || lhs.close !== rhs.close || lhs.volume !== rhs.volume ) { return false; } } return true; } function readCssVar(name: string, fallback: string) { if (typeof window === "undefined") return fallback; const value = window .getComputedStyle(document.documentElement) .getPropertyValue(name) .trim(); return value || fallback; }