From da17be89693b86318eb4c525af43471b483bda41 Mon Sep 17 00:00:00 2001 From: momentum dev Date: Fri, 31 Jul 2026 18:19:16 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20dashboard=20readability=20pass=20?= =?UTF-8?q?=E2=80=94=20type=20hierarchy,=20P&L=20masthead,=20trigger-row?= =?UTF-8?q?=20cleanup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Two-texture typography: labels move to the UI sans (11px, brighter muted #93a0bd), values stay tabular mono — label/value pairs parse instead of dissolving into uniform mono soup - TOTAL P&L is the one dominant instrument: 34px + green/red state wash and accent bar on the cell (CSS :has on the existing pos/neg classes, no JS) - Equity tile: available funds as a small sub-line (fixes the two-line wrap that broke the strip height) - Armed triggers: single-line ellipsized meta/levels (was a 3-line crumb wrap), 15px symbols, ARMED/WEAK state chips, subtle zebra, thinner bars, wider levels cell so entry/stop/now never clip - Verified with headless before/after renders against live data; zero JS logic changes, node --check clean Co-Authored-By: Claude Fable 5 --- api/static/dashboard.html | 53 ++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/api/static/dashboard.html b/api/static/dashboard.html index 03bcc3d..de2f039 100644 --- a/api/static/dashboard.html +++ b/api/static/dashboard.html @@ -12,8 +12,9 @@ --panel-hi: #1c2435; --border: #232c41; --border-soft: #18202f; - --text: #e3e8f2; - --muted: #7884a2; + --text: #e6ebf5; + --muted: #93a0bd; + --sans: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif; --accent: #5ba3ff; --accent-dim: #2a4a78; --green: #34d17e; @@ -143,8 +144,16 @@ transition: background .2s ease; } .pnl-cell:hover { background: rgba(91,163,255,.04); } - .pnl-cell .label { font: 600 10px var(--mono); text-transform: uppercase; letter-spacing: .7px; color: var(--muted); } - .pnl-cell .value { font: 650 20px var(--mono); margin-top: 3px; letter-spacing: -.3px; font-variant-numeric: tabular-nums; } + /* labels in the UI sans, values in mono — two textures so label/value pairs + parse at a glance instead of dissolving into one mono soup */ + .pnl-cell .label { font: 600 11px var(--sans); text-transform: uppercase; letter-spacing: .5px; color: var(--muted); } + .pnl-cell .value { font: 650 22px var(--mono); margin-top: 4px; letter-spacing: -.3px; font-variant-numeric: tabular-nums; } + /* signature: TOTAL P&L is the one instrument that dominates, and its cell + carries a state wash (green/red) readable from across the room */ + .pnl-cell:first-child .value { font-size: 34px; } + .pnl-cell:first-child:has(.value.pos) { background: linear-gradient(180deg, rgba(52,209,126,.10), transparent 75%); box-shadow: inset 3px 0 0 var(--green); } + .pnl-cell:first-child:has(.value.neg) { background: linear-gradient(180deg, rgba(255,90,96,.10), transparent 75%); box-shadow: inset 3px 0 0 var(--red); } + .funds-avail { display: block; font: 500 11px var(--sans); color: var(--muted); margin-top: 2px; letter-spacing: .2px; } #pnl-total { font-size: 27px; font-weight: 760; } .pos { color: var(--green); text-shadow: 0 0 20px var(--glow-green); } .neg { color: var(--red); text-shadow: 0 0 20px var(--glow-red); } @@ -188,9 +197,9 @@ details.panel[open] > summary > h2 { background: linear-gradient(180deg, var(--panel-hi), rgba(22,28,42,.5)); } #panels-toggle { margin-left: 4px; } .count { font: 600 11px var(--mono); background: var(--border); color: var(--text); border-radius: 10px; padding: 1px 8px; } - .hint { margin-left: auto; font: 500 10px var(--mono); color: var(--muted); letter-spacing: .3px; text-transform: none; } + .hint { margin-left: auto; font: 500 11px var(--sans); color: var(--muted); letter-spacing: .2px; text-transform: none; } table { width: 100%; border-collapse: collapse; } - th { text-align: left; font: 600 11px var(--mono); text-transform: uppercase; letter-spacing: .6px; color: var(--muted); padding: 8px 14px; border-bottom: 1px solid var(--border); } + th { text-align: left; font: 600 11px var(--sans); text-transform: uppercase; letter-spacing: .5px; color: var(--muted); padding: 8px 14px; border-bottom: 1px solid var(--border); } td { padding: 8px 14px; border-bottom: 1px solid #151a26; font-size: 13px; vertical-align: middle; } tr:last-child td { border-bottom: none; } .num { font-family: var(--mono); } @@ -268,22 +277,29 @@ .rdot.warn { color: #f1c40f; text-shadow: 0 0 12px rgba(241,196,15,.45); } .rdot.critical { color: #ff5a60; text-shadow: 0 0 12px rgba(255,77,79,.5); } /* armed-trigger proximity radar */ - .trig-row { display: flex; align-items: center; gap: 11px; padding: 6px 6px; + .trig-row { display: flex; align-items: center; gap: 12px; padding: 9px 8px; border-bottom: 1px solid var(--border); font: 600 12px var(--mono); } .trig-row:last-child { border-bottom: 0; } - .trig-sym { width: 62px; font-weight: 700; } - .trig-state { width: 52px; font-size: 9px; font-weight: 700; text-transform: uppercase; - letter-spacing: .5px; } - .trig-meta { width: 96px; color: var(--muted); font: 500 10px var(--mono); } - .trig-levels { width: 150px; color: var(--muted); font: 500 10px var(--mono); } + .trig-row:nth-child(even) { background: rgba(255,255,255,.016); } + .trig-sym { width: 68px; font-weight: 700; font-size: 15px; letter-spacing: .2px; } + .trig-state { width: 56px; font-size: 9px; font-weight: 700; text-transform: uppercase; + letter-spacing: .5px; text-align: center; padding: 3px 0; border-radius: 4px; + background: var(--panel-hi); } + .trig-state[data-state="armed"], .trig-state.armed { background: rgba(91,163,255,.16); color: var(--accent); } + /* single-line meta with ellipsis — the 3-line "gap 836% 3277.8x tod" crumb wrap + was the worst readability offender in the panel */ + .trig-meta { width: 148px; color: var(--muted); font: 500 11px var(--mono); + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + .trig-levels { width: 218px; color: var(--muted); font: 500 11px var(--mono); + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .trig-levels b { color: var(--text); font-weight: 700; } - .trig-bar { flex: 1; height: 16px; position: relative; background: #0d1117; - border: 1px solid var(--border); border-radius: 3px; overflow: hidden; min-width: 120px; } + .trig-bar { flex: 1; height: 10px; position: relative; background: #0d1117; + border: 1px solid var(--border-soft); border-radius: 5px; overflow: hidden; min-width: 120px; } .trig-fill { position: absolute; left: 0; top: 0; bottom: 0; transition: width .35s ease; } .trig-trigline { position: absolute; top: -1px; bottom: -1px; width: 2px; background: #e6edf3; box-shadow: 0 0 4px rgba(230,237,243,.6); } .trig-dist { width: 70px; text-align: right; font-weight: 700; } - .trig-cat { width: 196px; color: var(--accent); font: 500 10px var(--mono); overflow: hidden; + .trig-cat { width: 216px; color: var(--accent); font: 500 11px var(--sans); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .trig-adv { font: 600 10px var(--mono); color: #c9d3e6; } .trig-cat-raw { color: var(--muted); font: 500 10px var(--mono); } @@ -498,7 +514,7 @@
Win Rate
—
Avg R
—
Open / Closed
—
-
Equity / Avail
—
+
Equity
—
Day Curve
—
@@ -1182,7 +1198,7 @@ function renderTriggers(tw, catMap) { const near = (t.state === 'armed' && dist != null && dist > -1.0) ? ' near' : ''; return '
' + '
' + (t.catalyst ? '📰 ' : '') + esc(t.symbol) + '
' - + '
' + esc(t.state) + '
' + + '
' + esc(t.state) + '
' + '
' + (t.gap != null ? 'gap ' + t.gap.toFixed(0) + '% ' : '') + (t.rvol != null ? t.rvol.toFixed(1) + 'x' : '') + (t.rvol_tod != null ? ' \u00B7 tod ' + (t.rvol_tod >= 100 ? t.rvol_tod.toFixed(0) : t.rvol_tod.toFixed(1)) + 'x' : '') + '
' + '
entry ' + fmt(trig) + ' stop ' + fmt(stop) + ' now ' + fmt(price) + '
' + '
' @@ -1456,7 +1472,8 @@ function render(d) { if (acct0.account_id) { const eq = acct0.total_equity != null ? acct0.total_equity : acct0.net_liquidating_value; const avail = acct0.buying_power; - $("pnl-funds").textContent = money(eq) + " / " + (avail != null ? money(avail) : "—"); + $("pnl-funds").innerHTML = money(eq) + + 'avail ' + (avail != null ? money(avail) : "—") + ''; } else { $("pnl-funds").textContent = "—"; }