Skip to content

Commit dcb6d0a

Browse files
Merge pull request #7 from that-github-user/fix/analytics-wiring-mobile
Fix analytics wiring + mobile layout overflow
2 parents 4f8b8d4 + b7664f2 commit dcb6d0a

File tree

4 files changed

+91
-95
lines changed

4 files changed

+91
-95
lines changed

src/api/mock.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,23 @@ export function generateMockPrediction(): PredictionResponse {
120120
p10_return: +((drift - 0.08) * 0.01).toFixed(6),
121121
p90_return: +((drift + 0.08) * 0.01).toFixed(6),
122122
long_frac: +(0.5 + drift * 2).toFixed(4),
123+
// Analytics engine fields (nested in signal to match server)
124+
regime: regimeLabels[Math.floor(rand() * 4)],
125+
exhaustion_score: +(0.3 + rand() * 2.2).toFixed(2),
126+
ensemble_agreement: +(0.3 + rand() * 0.7).toFixed(2),
127+
signal_strength_percentile: Math.floor(rand() * 100),
128+
invalidation: {
129+
price_level: round(
130+
isLong ? lastClose - (4 + rand() * 8) : lastClose + (4 + rand() * 8),
131+
),
132+
price_direction: isLong ? "below" : isShort ? "above" : "either",
133+
description: isLong
134+
? "Close below support invalidates bullish thesis"
135+
: isShort
136+
? "Close above resistance invalidates bearish thesis"
137+
: "Breakout from range invalidates neutral stance",
138+
ensemble_contradiction: +(rand() * 0.4).toFixed(4),
139+
},
123140
},
124141
context_candles: contextCandles,
125142
// Analytics engine fields

src/api/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ export interface SignalResponse {
1616
p90_return: number;
1717
long_frac: number;
1818
horizon_signals?: Record<string, HorizonSignal> | null;
19+
// Analytics engine fields (nested in signal response from server)
20+
regime?: string | null;
21+
exhaustion_score?: number | null;
22+
ensemble_agreement?: number | null;
23+
signal_strength_percentile?: number | null;
24+
invalidation?: InvalidationInfo | null;
1925
}
2026

2127
export interface CandleData {

src/components/layout/Dashboard.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ export function Dashboard() {
264264
chartType={chartType}
265265
forecastStyle={forecastStyle}
266266
timeframe={timeframe}
267-
invalidationLevel={prediction.invalidation?.price_level ?? null}
267+
invalidationLevel={prediction.signal.invalidation?.price_level ?? prediction.invalidation?.price_level ?? null}
268268
highlightedPaths={highlightedPaths}
269269
trackingPath={trackingPath}
270270
showTracking={showTracking}
@@ -275,11 +275,11 @@ export function Dashboard() {
275275
{/* Sidebar: analytics cards */}
276276
<div className="sidebar-cards fade-in">
277277
<AnalyticsCards
278-
regime={prediction.regime ?? null}
279-
exhaustionScore={prediction.exhaustion_score ?? null}
280-
ensembleAgreement={prediction.ensemble_agreement ?? null}
281-
signalPercentile={prediction.signal_percentile ?? null}
282-
invalidation={prediction.invalidation ?? null}
278+
regime={prediction.signal.regime ? { label: prediction.signal.regime as "trending" | "mean-reverting" | "volatile" | "quiet", confidence: 0 } : prediction.regime ?? null}
279+
exhaustionScore={prediction.signal.exhaustion_score ?? prediction.exhaustion_score ?? null}
280+
ensembleAgreement={prediction.signal.ensemble_agreement ?? prediction.ensemble_agreement ?? null}
281+
signalPercentile={prediction.signal.signal_strength_percentile ?? prediction.signal_percentile ?? null}
282+
invalidation={prediction.signal.invalidation ?? prediction.invalidation ?? null}
283283
regimePerformance={prediction.regime_performance ?? null}
284284
lastClose={prediction.last_close}
285285
direction={prediction.signal.direction}
@@ -295,7 +295,7 @@ export function Dashboard() {
295295
<SignalPanel
296296
signal={prediction.signal}
297297
lastClose={prediction.last_close}
298-
regime={prediction.regime}
298+
regime={prediction.signal.regime ? { label: prediction.signal.regime as "trending" | "mean-reverting" | "volatile" | "quiet", confidence: 0 } : prediction.regime ?? null}
299299
/>
300300
</div>
301301
<div className="fade-in">
@@ -305,7 +305,7 @@ export function Dashboard() {
305305
numTrades={liveStats.numTrades}
306306
historyError={historyError}
307307
rangeAccuracy={rangeMetrics}
308-
regimeLabel={prediction.regime?.label}
308+
regimeLabel={prediction.signal.regime ?? prediction.regime?.label ?? null}
309309
/>
310310
</div>
311311
</>

src/styles/globals.css

Lines changed: 60 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,6 @@ html, body, #root {
174174
padding: 0 4px;
175175
}
176176

177-
.table-scroll .summary-table {
178-
min-width: 600px;
179-
}
180-
181177
/* ── Value flash animation ── */
182178
.value-transition {
183179
transition: color 0.3s ease, transform 0.2s ease;
@@ -502,55 +498,6 @@ html, body, #root {
502498
text-align: center;
503499
}
504500

505-
/* ── Backtest page ── */
506-
.backtest-container {
507-
min-height: 100vh;
508-
background: var(--bg-base);
509-
color: var(--text-primary);
510-
padding: 20px;
511-
overflow-y: auto;
512-
}
513-
514-
.backtest-inner {
515-
max-width: 1100px;
516-
margin: 0 auto;
517-
}
518-
519-
/* ── Summary table ── */
520-
.summary-table {
521-
width: 100%;
522-
border-collapse: collapse;
523-
font-family: var(--font-mono);
524-
font-size: 12px;
525-
}
526-
527-
.summary-table th {
528-
text-align: left;
529-
padding: 8px 12px;
530-
color: var(--text-muted);
531-
font-weight: 500;
532-
font-size: 10px;
533-
text-transform: uppercase;
534-
letter-spacing: 0.5px;
535-
border-bottom: 1px solid var(--border-dim);
536-
white-space: nowrap;
537-
}
538-
539-
.summary-table td {
540-
padding: 8px 12px;
541-
border-bottom: 1px solid var(--bg-elevated);
542-
color: var(--text-primary);
543-
white-space: nowrap;
544-
}
545-
546-
.summary-table tr:hover td {
547-
background: rgba(59, 130, 246, 0.05);
548-
}
549-
550-
.pf-good { color: var(--accent-green); }
551-
.pf-ok { color: var(--accent-amber); }
552-
.pf-bad { color: var(--accent-red); }
553-
554501
/* ── Responsive: sidebar shrink ── */
555502
@media (max-width: 1200px) {
556503
.dashboard-grid {
@@ -597,31 +544,53 @@ html, body, #root {
597544

598545
.fan-chart-cell {
599546
grid-area: auto;
600-
min-height: 350px;
547+
min-height: 300px;
601548
height: 50vh;
549+
overflow: hidden;
602550
}
603551

604-
.sidebar-cards { grid-area: auto; }
605-
.sidebar-middle { grid-area: auto; overflow: visible; }
606-
.sidebar-equity { grid-area: auto; }
552+
.sidebar-cards {
553+
grid-area: auto;
554+
}
607555

608-
.panel-header {
609-
flex-wrap: wrap;
610-
gap: 6px;
556+
.sidebar-cards .analytics-cards {
557+
grid-template-columns: 1fr 1fr;
558+
gap: 3px;
611559
}
612560

613-
.panel-controls {
614-
flex-wrap: wrap;
615-
gap: 4px;
561+
.sidebar-cards .analytics-card {
562+
padding: 6px 8px;
563+
}
564+
565+
.sidebar-cards .analytics-card .card-value {
566+
font-size: 13px;
616567
}
617568

618569
.sidebar-middle {
570+
grid-area: auto;
619571
overflow: visible;
620572
min-height: auto;
621573
}
622574

623575
.sidebar-equity {
624-
min-height: 200px;
576+
grid-area: auto;
577+
min-height: 180px;
578+
}
579+
580+
.panel-header {
581+
flex-wrap: wrap;
582+
gap: 4px;
583+
}
584+
585+
.panel-controls {
586+
flex-wrap: wrap;
587+
gap: 3px;
588+
}
589+
590+
.panel-controls .toggle-group,
591+
.panel-controls .toggle-btn-solo {
592+
font-size: 9px;
593+
padding: 2px 6px;
625594
}
626595

627596
.tab-bar {
@@ -660,15 +629,6 @@ html, body, #root {
660629
grid-template-columns: 1fr;
661630
}
662631

663-
/* Backtest page */
664-
.backtest-container {
665-
padding: 12px;
666-
}
667-
668-
.backtest-inner {
669-
max-width: 100%;
670-
}
671-
672632
.stat-card .stat-value {
673633
font-size: 18px;
674634
}
@@ -685,29 +645,42 @@ html, body, #root {
685645
}
686646

687647
.fan-chart-cell {
688-
min-height: 280px;
689-
height: 45vh;
648+
min-height: 250px;
649+
height: 40vh;
650+
overflow: hidden;
690651
}
691652

692-
.sidebar-equity {
693-
min-height: 180px;
653+
.sidebar-cards .analytics-cards {
654+
grid-template-columns: 1fr 1fr;
655+
gap: 2px;
694656
}
695657

696-
.backtest-container {
697-
padding: 8px;
658+
.sidebar-cards .analytics-card {
659+
padding: 4px 6px;
698660
}
699661

700-
/* Stat grid: single column on phones */
701-
.stat-grid {
702-
grid-template-columns: 1fr;
703-
gap: 8px;
662+
.sidebar-cards .analytics-card .card-value {
663+
font-size: 12px;
704664
}
705665

706-
.stat-card {
707-
padding: 10px;
666+
.sidebar-cards .analytics-card .card-label {
667+
font-size: 8px;
708668
}
709669

710-
.stat-card .stat-value {
711-
font-size: 16px;
670+
.sidebar-cards .analytics-card .card-sub {
671+
display: none;
672+
}
673+
674+
.sidebar-equity {
675+
min-height: 150px;
676+
}
677+
678+
.scenario-card .scenario-label {
679+
min-width: 70px;
680+
font-size: 10px;
681+
}
682+
683+
.scenario-card .scenario-sparkline {
684+
display: none;
712685
}
713686
}

0 commit comments

Comments
 (0)