diff --git a/web/src/App.tsx b/web/src/App.tsx index 6f785908..c7107023 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -194,8 +194,9 @@ function App() {
{/* Header - Binance Style */}
-
-
+
+ {/* Desktop Layout */} +
{/* Left - Logo and Title */}
@@ -210,7 +211,7 @@ function App() {

- + {/* Center - Page Toggle (absolutely positioned) */}
- + {/* Right - Actions */}
@@ -257,7 +258,7 @@ function App() { {user.email}
)} - + {/* Admin Mode Indicator */} {systemConfig?.admin_mode && (
@@ -302,11 +303,118 @@ function App() { )}
+ + {/* Mobile Layout */} +
+ {/* Top Row - Logo, Title and Language */} +
+
+ NOFX +
+

+ {t('appTitle', language)} +

+

+ {t('subtitle', language)} +

+
+
+ + {/* Language Toggle - Right side on mobile */} +
+ + +
+
+ + {/* Second Row - Page Toggle */} +
+ + + +
+ + {/* Third Row - User Info and Logout */} +
+ {/* User Info or Admin Mode */} + {!systemConfig?.admin_mode && user && ( +
+
+ {user.email[0].toUpperCase()} +
+ {user.email} +
+ )} + + {systemConfig?.admin_mode && ( +
+ + {t('adminMode', language)} +
+ )} + + {/* Logout Button */} + {!systemConfig?.admin_mode && ( + + )} +
+
{/* Main Content */} -
+
{currentPage === 'competition' ? ( ) : currentPage === 'traders' ? ( diff --git a/web/src/components/AITradersPage.tsx b/web/src/components/AITradersPage.tsx index d534c0b0..6044a73a 100644 --- a/web/src/components/AITradersPage.tsx +++ b/web/src/components/AITradersPage.tsx @@ -458,22 +458,22 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { }; return ( -
+
{/* Header */} -
-
-
+
+
- +
-

+

{t('aiTraders', language)} - {traders?.length || 0} {t('active', language)} @@ -483,37 +483,37 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) {

- -
+ +
- +
{/* Configuration Status */} -
+
{/* AI Models */} -
-

- +
+

+ {t('aiModels', language)}

-
+
{configuredModels.map(model => { const inUse = isModelInUse(model.id); return ( -
handleModelClick(model.id)} > -
-
- {getModelIcon(model.provider || model.id, { width: 32, height: 32 }) || ( -
+
+ {getModelIcon(model.provider || model.id, { width: 28, height: 28 }) || ( +
@@ -570,63 +570,63 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) {
)}
-
-
{getShortName(model.name)}
+
+
{getShortName(model.name)}
{inUse ? t('inUse', language) : model.enabled ? t('enabled', language) : t('configured', language)}
-
+
); })} {configuredModels.length === 0 && ( -
- -
{t('noModelsConfigured', language)}
+
+ +
{t('noModelsConfigured', language)}
)}
{/* Exchanges */} -
-

- +
+

+ {t('exchanges', language)}

-
+
{configuredExchanges.map(exchange => { const inUse = isExchangeInUse(exchange.id); return ( -
handleExchangeClick(exchange.id)} > -
-
- {getExchangeIcon(exchange.id, { width: 32, height: 32 })} +
+
+ {getExchangeIcon(exchange.id, { width: 28, height: 28 })}
-
-
{getShortName(exchange.name)}
+
+
{getShortName(exchange.name)}
{exchange.type.toUpperCase()} • {inUse ? t('inUse', language) : exchange.enabled ? t('enabled', language) : t('configured', language)}
-
+
); })} {configuredExchanges.length === 0 && ( -
- -
{t('noExchangesConfigured', language)}
+
+ +
{t('noExchangesConfigured', language)}
)}
@@ -634,47 +634,47 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) {
{/* Traders List */} -
-
-

- +
+
+

+ {t('currentTraders', language)}

{traders && traders.length > 0 ? ( -
+
{traders.map(trader => (
-
-
+
- +
-
-
+
+
{trader.trader_name}
-
{getModelDisplayName(trader.ai_model.split('_').pop() || trader.ai_model)} Model • {trader.exchange_id?.toUpperCase()}
-
+
{/* Status */}
{t('status', language)}
-
@@ -683,20 +683,20 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) {
{/* Actions */} -
+
- +
@@ -729,15 +729,15 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { ))}
) : ( -
- -
{t('noTraders', language)}
-
{t('createFirstTrader', language)}
+
+ +
{t('noTraders', language)}
+
{t('createFirstTrader', language)}
{(configuredModels.length === 0 || configuredExchanges.length === 0) && ( -
- {configuredModels.length === 0 && configuredExchanges.length === 0 +
+ {configuredModels.length === 0 && configuredExchanges.length === 0 ? t('configureModelsAndExchangesFirst', language) - : configuredModels.length === 0 + : configuredModels.length === 0 ? t('configureModelsFirst', language) : t('configureExchangesFirst', language) } diff --git a/web/src/components/ComparisonChart.tsx b/web/src/components/ComparisonChart.tsx index e8d1fafe..ebd56305 100644 --- a/web/src/components/ComparisonChart.tsx +++ b/web/src/components/ComparisonChart.tsx @@ -313,24 +313,24 @@ export function ComparisonChart({ traders }: ComparisonChartProps) {
{/* Stats */} -
-
+
+
{t('comparisonMode', language)}
-
PnL %
+
PnL %
-
+
{t('dataPoints', language)}
-
{t('count', language, {count: combinedData.length})}
+
{t('count', language, {count: combinedData.length})}
-
+
{t('currentGap', language)}
-
1 ? '#F0B90B' : '#EAECEF' }}> +
1 ? '#F0B90B' : '#EAECEF' }}> {currentGap.toFixed(2)}%
-
+
{t('displayRange', language)}
-
+
{combinedData.length > MAX_DISPLAY_POINTS ? `${t('recent', language)} ${MAX_DISPLAY_POINTS}` : t('allData', language)} diff --git a/web/src/components/CompetitionPage.tsx b/web/src/components/CompetitionPage.tsx index 1ebdb564..fcd332d4 100644 --- a/web/src/components/CompetitionPage.tsx +++ b/web/src/components/CompetitionPage.tsx @@ -73,13 +73,16 @@ export function CompetitionPage() { return (
{/* Competition Header - 精简版 */} -
-
-
- +
+
+
+
-

+

{t('aiCompetition', language)} {competition.count} {t('traders', language)} @@ -90,9 +93,9 @@ export function CompetitionPage() {

-
+
{t('leader', language)}
-
{leader?.trader_name}
+
{leader?.trader_name}
= 0 ? '#0ECB81' : '#F6465D' }}> {(leader?.total_pnl ?? 0) >= 0 ? '+' : ''}{leader?.total_pnl_pct?.toFixed(2) || '0.00'}%
@@ -155,20 +158,20 @@ export function CompetitionPage() {
{/* Stats */} -
+
{/* Total Equity */}
{t('equity', language)}
-
+
{trader.total_equity?.toFixed(2) || '0.00'}
{/* P&L */} -
+
{t('pnl', language)}
= 0 ? '#0ECB81' : '#F6465D' }} > {(trader.total_pnl ?? 0) >= 0 ? '+' : ''} @@ -182,7 +185,7 @@ export function CompetitionPage() { {/* Positions */}
{t('pos', language)}
-
+
{trader.position_count}
@@ -242,15 +245,12 @@ export function CompetitionPage() { >
{trader.trader_name}
-
- {trader.ai_model.toUpperCase()} + {trader.exchange.toUpperCase()} -
-
= 0 ? '#0ECB81' : '#F6465D' }}> +
= 0 ? '#0ECB81' : '#F6465D' }}> {(trader.total_pnl ?? 0) >= 0 ? '+' : ''}{trader.total_pnl_pct?.toFixed(2) || '0.00'}%
{isWinning && gap > 0 && (