feat: reasoning timeline on armed-trigger rows (click to expand)
The day's relevant names live in ARMED TRIGGERS — the reasoning panel now opens right there: click a trigger row for the score/rvol timelines, criteria lanes, and worded reasons, same renderer as the watch panel. Caret + hover affordance; open panels survive snapshot re-renders. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2be23673be
commit
a6da02f809
1 file changed
+33
-3
@@ -303,6 +303,11 @@
|
||||
border-bottom: 1px solid var(--border); font: 600 12px var(--mono); }
|
||||
.trig-row:last-child { border-bottom: 0; }
|
||||
.trig-row:nth-child(even) { background: rgba(255,255,255,.016); }
|
||||
.trig-row { cursor: pointer; }
|
||||
.trig-row:hover { background: rgba(91,163,255,.05); }
|
||||
.trig-row.open { background: rgba(91,163,255,.07); border-bottom: 0; }
|
||||
.trig-detail { border-bottom: 1px solid var(--border-soft);
|
||||
background: rgba(13,17,23,.4); padding-bottom: 6px; }
|
||||
.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;
|
||||
@@ -1263,7 +1268,27 @@ function trigCatalyst(adv, rawHeadline) {
|
||||
return '<span class="trig-adv" title="' + esc(tip) + '">' + dot + ' ' + esc(typ) + badge + '</span>';
|
||||
}
|
||||
|
||||
// click a trigger row -> same reasoning timeline as the watch panel, right
|
||||
// where the day's relevant names live
|
||||
const trigExpanded = new Set();
|
||||
let lastTrigArgs = null;
|
||||
async function toggleTrigReasoning(symbol) {
|
||||
if (trigExpanded.has(symbol)) trigExpanded.delete(symbol); else trigExpanded.add(symbol);
|
||||
if (lastTrigArgs) renderTriggers(lastTrigArgs[0], lastTrigArgs[1]);
|
||||
}
|
||||
function fillTrigReasoning() {
|
||||
trigExpanded.forEach(async (symbol) => {
|
||||
const hostEl = document.querySelector('[data-trig-crit="' + CSS.escape(symbol) + '"]');
|
||||
if (hostEl && hostEl.querySelector(".empty")) {
|
||||
try {
|
||||
const r = await fetch("/api/criteria?symbol=" + encodeURIComponent(symbol));
|
||||
hostEl.innerHTML = renderCriteriaGrid(await r.json());
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
}
|
||||
function renderTriggers(tw, catMap) {
|
||||
lastTrigArgs = [tw, catMap];
|
||||
const arr = (tw && tw.triggers) || [];
|
||||
const cat = catMap || {};
|
||||
$("trig-count").textContent = tw && tw.armed != null ? tw.armed : 0;
|
||||
@@ -1285,8 +1310,10 @@ function renderTriggers(tw, catMap) {
|
||||
const distTxt = fired ? '▲' : (dist != null ? (dist >= 0 ? '▲ ' : '') + dist.toFixed(1) + '%' : '—');
|
||||
const distCls = dist == null ? '' : (dist >= 0 ? 'pos' : dist > -1 ? 'warn' : 'neg');
|
||||
const near = (t.state === 'armed' && dist != null && dist > -1.0) ? ' near' : '';
|
||||
return '<div class="trig-row st-' + esc(t.state) + near + '">'
|
||||
+ '<div class="trig-sym">' + (t.catalyst ? '📰 ' : '') + esc(t.symbol) + '</div>'
|
||||
const isOpen = trigExpanded.has(t.symbol);
|
||||
return '<div class="trig-row st-' + esc(t.state) + near + (isOpen ? ' open' : '')
|
||||
+ '" onclick="toggleTrigReasoning(\'' + esc(t.symbol) + '\')" title="click for the reasoning timeline">'
|
||||
+ '<div class="trig-sym"><span class="caret ' + (isOpen ? "open" : "") + '">▶</span> ' + (t.catalyst ? '📰 ' : '') + esc(t.symbol) + '</div>'
|
||||
+ '<div class="trig-state ' + (String(t.state).toLowerCase() === "armed" ? "armed" : "") + '">' + esc(t.state) + '</div>'
|
||||
+ '<div class="trig-meta">' + (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' : '') + '</div>'
|
||||
+ '<div class="trig-levels">entry <b>' + fmt(trig) + '</b> stop <b>' + fmt(stop) + '</b> now ' + fmt(price) + '</div>'
|
||||
@@ -1295,8 +1322,11 @@ function renderTriggers(tw, catMap) {
|
||||
+ '</div>'
|
||||
+ '<div class="trig-dist ' + distCls + '">' + distTxt + '</div>'
|
||||
+ '<div class="trig-cat">' + trigCatalyst(cat[(t.symbol || '').toUpperCase()] || cat[t.symbol], t.catalyst) + '</div>'
|
||||
+ '</div>';
|
||||
+ '</div>'
|
||||
+ (isOpen ? '<div class="trig-detail" data-trig-crit="' + esc(t.symbol)
|
||||
+ '"><div class="empty" style="padding:12px 16px">loading…</div></div>' : '');
|
||||
}).join('');
|
||||
fillTrigReasoning();
|
||||
}
|
||||
|
||||
// catalyst engine status chip (shows the LLM news engine is live + its activity)
|
||||
|
||||
Reference in new issue
Block a user