-
Notifications
You must be signed in to change notification settings - Fork 7.3k
feat(forecast): simulation confidence sub-bar in ForecastPanel #2526
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -199,6 +199,16 @@ function injectStyles(): void { | |||||||||
| .fc-signal { color: var(--text-secondary, #a0a0a0); font-size: 11px; padding: 3px 0 3px 12px; line-height: 1.45; position: relative; margin-top: 2px; } | ||||||||||
| .fc-signal::before { content: ''; position: absolute; left: 0; top: 9px; display: inline-block; width: 6px; height: 1px; background: var(--text-secondary, #555); } | ||||||||||
| .fc-empty { padding: 20px; text-align: center; color: var(--text-secondary, #888); } | ||||||||||
|
|
||||||||||
| /* ── Simulation confidence sub-bar (Option D) ────────────────────────── */ | ||||||||||
| /* Thin colored underbar below the forecast title. Width encodes sim */ | ||||||||||
| /* path confidence. At rest: barely visible. On row hover: full opacity */ | ||||||||||
| /* + text label reveals below the bar. Zero extra columns needed. */ | ||||||||||
| .fc-sim-bar-wrap { margin-top: 4px; } | ||||||||||
| .fc-sim-bar { height: 2px; border-radius: 1px; opacity: 0.45; transition: opacity 0.15s; } | ||||||||||
| .fc-prob-item:hover .fc-sim-bar { opacity: 0.9; } | ||||||||||
| .fc-sim-label { font-size: 9px; display: none; margin-top: 2px; line-height: 1.2; } | ||||||||||
| .fc-prob-item:hover .fc-sim-label { display: block; } | ||||||||||
| `; | ||||||||||
| document.head.appendChild(style); | ||||||||||
| } | ||||||||||
|
|
@@ -439,13 +449,17 @@ export class ForecastPanel extends Panel { | |||||||||
| ).join('')}` | ||||||||||
| : ''; | ||||||||||
|
|
||||||||||
| const simBarHtml = this.renderSimBar(f); | ||||||||||
| const demoted = f.demotedBySimulation ?? false; | ||||||||||
|
|
||||||||||
| return ` | ||||||||||
| <div class="fc-prob-item"> | ||||||||||
| <div class="fc-prob-row"> | ||||||||||
| <span class="fc-prob-label" | ||||||||||
| style="border-left:2px solid ${catColor}47;padding-left:6px"> | ||||||||||
| <div class="fc-prob-row"${demoted ? ' style="opacity:0.5"' : ''}> | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
CSS For demoted forecasts this is most important — the "AI flag: dropped" label is the signal users most need to read. One approach is to apply the dimming to the title text only (rather than the whole row), leaving the sim bar and label at full stacking opacity:
Suggested change
Alternatively, move the dimming to the individual text/bar cells so the sim-bar-wrap can opt out. |
||||||||||
| <div class="fc-prob-label" | ||||||||||
| style="border-left:2px solid ${catColor}47;padding-left:6px"> | ||||||||||
| ${escapeHtml(f.title)} | ||||||||||
| </span> | ||||||||||
| ${simBarHtml} | ||||||||||
| </div> | ||||||||||
| <div class="fc-bar-wrap"> | ||||||||||
| <div class="fc-prob-bar-track"> | ||||||||||
| <div class="fc-prob-bar-fill" style="background:${probColor};width:${pct}%"></div> | ||||||||||
|
|
@@ -468,6 +482,40 @@ export class ForecastPanel extends Panel { | |||||||||
| `; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // ── Simulation confidence sub-bar ─────────────────────────────────────── | ||||||||||
|
|
||||||||||
| private renderSimBar(f: Forecast): string { | ||||||||||
| const adj = f.simulationAdjustment ?? 0; | ||||||||||
| if (adj === 0) return ''; | ||||||||||
|
|
||||||||||
| const conf = f.simPathConfidence ?? 1.0; | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The proto comment explicitly documents The correct fallback is
Suggested change
With proto3 wire encoding this |
||||||||||
| const demoted = f.demotedBySimulation ?? false; | ||||||||||
| const adjPct = Math.round(Math.abs(adj) * 100); | ||||||||||
|
|
||||||||||
| let barColor: string; | ||||||||||
| let labelText: string; | ||||||||||
|
|
||||||||||
| if (demoted) { | ||||||||||
| barColor = '#e05252'; | ||||||||||
| labelText = `AI flag: dropped · −${adjPct}%`; | ||||||||||
| } else if (adj > 0) { | ||||||||||
| barColor = conf >= 0.70 ? '#3fb950' : '#d29922'; | ||||||||||
| labelText = conf < 0.70 ? `AI signal (moderate) · +${adjPct}%` : `AI signal · +${adjPct}%`; | ||||||||||
| } else { | ||||||||||
| barColor = '#ea580c'; | ||||||||||
| labelText = `AI caution · −${adjPct}%`; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // Width encodes sim-path confidence for positive adjustments (at least 20% so bar is visible). | ||||||||||
| // Negative adjustments use 100% width — structural signal, not confidence-dependent. | ||||||||||
| const barWidthPct = adj > 0 ? Math.round(Math.max(20, conf * 100)) : 100; | ||||||||||
|
|
||||||||||
| return `<div class="fc-sim-bar-wrap"> | ||||||||||
| <div class="fc-sim-bar" style="width:${barWidthPct}%;background:${barColor}"></div> | ||||||||||
| <span class="fc-sim-label" style="color:${barColor}">${escapeHtml(labelText)}</span> | ||||||||||
| </div>`; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // ── Detail sections (shared by rows) ──────────────────────────────────── | ||||||||||
|
|
||||||||||
| private renderDetailBody(f: Forecast): string { | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.fc-prob-rowis a CSS Grid withalign-items: center. When.fc-sim-labelswitches fromdisplay: nonetodisplay: blockon hover, the first grid column (.fc-prob-label) grows taller, re-centering all other columns (probability bar, trend, domain tag) to the new row height. This produces a visible layout shift and can make adjacent cells feel jittery, particularly noticeable when quickly scanning forecasts.Consider
visibility: hidden+height: 1.2eminstead of togglingdisplay, so the row height is always reserved:This pre-allocates the space even when the label is hidden and avoids the reflow.