From 5f036d7669822a68b4dbbeae336682ef3569d9d8 Mon Sep 17 00:00:00 2001 From: tinkle-community Date: Thu, 30 Oct 2025 22:21:57 +0800 Subject: [PATCH] UI: Unify trader colors between Leaderboard and Performance Chart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: - Leaderboard used ai_model-based colors (qwen=purple, other=blue) - Performance Comparison used index-based colors (10 color pool) - This caused color mismatch between the two components - Same trader showed different colors in different sections Solution: - Create shared color utility (utils/traderColors.ts) - Define single color pool with 10 distinct colors - Implement unified getTraderColor function based on trader index - Update both ComparisonChart and CompetitionPage to use shared utility Changes: - New file: web/src/utils/traderColors.ts (shared color logic) - Updated: ComparisonChart.tsx (use shared utility) - Updated: CompetitionPage.tsx (use shared utility in Leaderboard and Head-to-Head sections) Now traders consistently display the same color across all UI sections. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: tinkle-community --- web/src/components/ComparisonChart.tsx | 35 +++++++------------------- web/src/components/CompetitionPage.tsx | 7 +++--- web/src/utils/traderColors.ts | 31 +++++++++++++++++++++++ 3 files changed, 44 insertions(+), 29 deletions(-) create mode 100644 web/src/utils/traderColors.ts diff --git a/web/src/components/ComparisonChart.tsx b/web/src/components/ComparisonChart.tsx index 4cf2e007..b49ff4b1 100644 --- a/web/src/components/ComparisonChart.tsx +++ b/web/src/components/ComparisonChart.tsx @@ -13,6 +13,7 @@ import { import useSWR from 'swr'; import { api } from '../lib/api'; import type { CompetitionTraderData } from '../types'; +import { getTraderColor } from '../utils/traderColors'; interface ComparisonChartProps { traders: CompetitionTraderData[]; @@ -177,26 +178,8 @@ export function ComparisonChart({ traders }: ComparisonChartProps) { ]; }; - // Trader颜色配置 - 为每个trader分配不同的颜色 - // 使用更丰富的颜色池,确保多个trader时不重复 - const TRADER_COLORS = [ - '#60a5fa', // blue-400 - '#c084fc', // purple-400 - '#34d399', // emerald-400 - '#fb923c', // orange-400 - '#f472b6', // pink-400 - '#fbbf24', // amber-400 - '#38bdf8', // sky-400 - '#a78bfa', // violet-400 - '#4ade80', // green-400 - '#fb7185', // rose-400 - ]; - - const getTraderColor = (traderId: string) => { - const traderIndex = traders.findIndex((t) => t.trader_id === traderId); - // 如果超出颜色池大小,循环使用 - return TRADER_COLORS[traderIndex % TRADER_COLORS.length]; - }; + // 使用统一的颜色分配逻辑(与Leaderboard保持一致) + const traderColor = (traderId: string) => getTraderColor(traders, traderId); // 自定义Tooltip - Binance Style const CustomTooltip = ({ active, payload }: any) => { @@ -216,7 +199,7 @@ export function ComparisonChart({ traders }: ComparisonChartProps) {
{trader.trader_name}
@@ -257,8 +240,8 @@ export function ComparisonChart({ traders }: ComparisonChartProps) { x2="0" y2="1" > - - + + ))} @@ -305,10 +288,10 @@ export function ComparisonChart({ traders }: ComparisonChartProps) { key={trader.trader_id} type="monotone" dataKey={`${trader.trader_id}_pnl_pct`} - stroke={getTraderColor(trader.trader_id)} + stroke={traderColor(trader.trader_id)} strokeWidth={3} - dot={displayData.length < 50 ? { fill: getTraderColor(trader.trader_id), r: 3 } : false} - activeDot={{ r: 6, fill: getTraderColor(trader.trader_id), stroke: '#fff', strokeWidth: 2 }} + dot={displayData.length < 50 ? { fill: traderColor(trader.trader_id), r: 3 } : false} + activeDot={{ r: 6, fill: traderColor(trader.trader_id), stroke: '#fff', strokeWidth: 2 }} name={trader.trader_name} connectNulls /> diff --git a/web/src/components/CompetitionPage.tsx b/web/src/components/CompetitionPage.tsx index ca67447c..a6746f20 100644 --- a/web/src/components/CompetitionPage.tsx +++ b/web/src/components/CompetitionPage.tsx @@ -4,6 +4,7 @@ import type { CompetitionData } from '../types'; import { ComparisonChart } from './ComparisonChart'; import { useLanguage } from '../contexts/LanguageContext'; import { t } from '../i18n/translations'; +import { getTraderColor } from '../utils/traderColors'; export function CompetitionPage() { const { language } = useLanguage(); @@ -108,7 +109,7 @@ export function CompetitionPage() {
{sortedTraders.map((trader, index) => { const isLeader = index === 0; - const aiModelColor = trader.ai_model === 'qwen' ? '#c084fc' : '#60a5fa'; + const traderColor = getTraderColor(sortedTraders, trader.trader_id); return (
{trader.trader_name}
-
+
{trader.ai_model.toUpperCase()}
@@ -223,7 +224,7 @@ export function CompetitionPage() {
{trader.trader_name}
diff --git a/web/src/utils/traderColors.ts b/web/src/utils/traderColors.ts new file mode 100644 index 00000000..fb884ded --- /dev/null +++ b/web/src/utils/traderColors.ts @@ -0,0 +1,31 @@ +// Trader颜色配置 - 统一的颜色分配逻辑 +// 用于 ComparisonChart 和 Leaderboard,确保颜色一致性 + +export const TRADER_COLORS = [ + '#60a5fa', // blue-400 + '#c084fc', // purple-400 + '#34d399', // emerald-400 + '#fb923c', // orange-400 + '#f472b6', // pink-400 + '#fbbf24', // amber-400 + '#38bdf8', // sky-400 + '#a78bfa', // violet-400 + '#4ade80', // green-400 + '#fb7185', // rose-400 +]; + +/** + * 根据trader的索引位置获取颜色 + * @param traders - trader列表 + * @param traderId - 当前trader的ID + * @returns 对应的颜色值 + */ +export function getTraderColor( + traders: Array<{ trader_id: string }>, + traderId: string +): string { + const traderIndex = traders.findIndex((t) => t.trader_id === traderId); + if (traderIndex === -1) return TRADER_COLORS[0]; // 默认返回第一个颜色 + // 如果超出颜色池大小,循环使用 + return TRADER_COLORS[traderIndex % TRADER_COLORS.length]; +}