feat(rflows): funnel config threshold bar + extend slider to $5000

Replace three threshold dot rows with a single red→yellow→green color bar.
Extend outflow slider range from $3000 to $5000.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-03-11 17:10:17 -07:00
parent 4199a8c6e0
commit c2c3d1fb06
2 changed files with 26 additions and 24 deletions

View File

@ -756,18 +756,13 @@
min-width: 40px; text-align: right; min-width: 40px; text-align: right;
} }
/* Derived threshold info */ /* Threshold color bar */
.icp-derived-info { .icp-threshold-bar-wrap { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--rs-border-subtle); }
margin-top: 6px; padding: 6px 0 0; .icp-threshold-bar { display: flex; height: 6px; border-radius: 3px; overflow: hidden; gap: 1px; }
border-top: 1px solid var(--rs-border-subtle); .icp-threshold-seg--red { background: var(--rflows-status-critical, #ef4444); }
} .icp-threshold-seg--yellow { background: var(--rflows-status-sustained, #eab308); }
.icp-derived-row { .icp-threshold-seg--green { background: var(--rflows-status-thriving, #10b981); }
display: flex; align-items: center; gap: 6px; .icp-threshold-labels { display: flex; justify-content: space-between; font-size: 9px; color: var(--rs-text-muted); margin-top: 2px; }
font-size: 10px; color: var(--rs-text-secondary); margin-bottom: 3px;
}
.icp-derived-dot {
width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
}
/* Analytics bars */ /* Analytics bars */
.icp-analytics-row { .icp-analytics-row {

View File

@ -2873,13 +2873,20 @@ class FolkFlowsApp extends HTMLElement {
<input class="icp-input" data-icp-field="label" value="${this.esc(d.label)}"/></div> <input class="icp-input" data-icp-field="label" value="${this.esc(d.label)}"/></div>
<div class="icp-range-group"> <div class="icp-range-group">
<span class="icp-range-label">$/mo</span> <span class="icp-range-label">$/mo</span>
<input class="icp-range" type="range" min="0" max="3000" step="50" value="${outflow}" data-icp-outflow="desiredOutflow"/> <input class="icp-range" type="range" min="0" max="5000" step="50" value="${outflow}" data-icp-outflow="desiredOutflow"/>
<span class="icp-range-value">${this.formatDollar(outflow)}</span> <span class="icp-range-value">${this.formatDollar(outflow)}</span>
</div> </div>
<div class="icp-derived-info"> <div class="icp-threshold-bar-wrap">
<div class="icp-derived-row"><span class="icp-derived-dot" style="background:var(--rflows-status-critical)"></span>Min (1mo): ${this.formatDollar(d.minThreshold)}</div> <div class="icp-threshold-bar">
<div class="icp-derived-row"><span class="icp-derived-dot" style="background:var(--rflows-status-sustained)"></span>Sufficient (4mo): ${this.formatDollar(d.sufficientThreshold ?? d.maxThreshold)}</div> <div class="icp-threshold-seg icp-threshold-seg--red" style="flex:1"></div>
<div class="icp-derived-row"><span class="icp-derived-dot" style="background:var(--rflows-status-thriving)"></span>Overflow (6mo): ${this.formatDollar(d.maxThreshold)}</div> <div class="icp-threshold-seg icp-threshold-seg--yellow" style="flex:3"></div>
<div class="icp-threshold-seg icp-threshold-seg--green" style="flex:2"></div>
</div>
<div class="icp-threshold-labels" data-icp-thresholds>
<span>${this.formatDollar(d.minThreshold)}</span>
<span>${this.formatDollar(d.sufficientThreshold ?? d.maxThreshold)}</span>
<span>${this.formatDollar(d.maxThreshold)}</span>
</div>
</div>`; </div>`;
} }
@ -3252,13 +3259,13 @@ class FolkFlowsApp extends HTMLElement {
fd.maxCapacity = derived.maxCapacity; fd.maxCapacity = derived.maxCapacity;
const valueSpan = input.parentElement?.querySelector(".icp-range-value") as HTMLElement; const valueSpan = input.parentElement?.querySelector(".icp-range-value") as HTMLElement;
if (valueSpan) valueSpan.textContent = this.formatDollar(val); if (valueSpan) valueSpan.textContent = this.formatDollar(val);
// Update derived info display // Update threshold bar labels
const info = overlay.querySelector(".icp-derived-info"); const thresholds = overlay.querySelector("[data-icp-thresholds]");
if (info) { if (thresholds) {
const rows = info.querySelectorAll(".icp-derived-row"); const spans = thresholds.querySelectorAll("span");
if (rows[0]) rows[0].innerHTML = `<span class="icp-derived-dot" style="background:var(--rflows-status-critical)"></span>Min (1mo): ${this.formatDollar(derived.minThreshold)}`; if (spans[0]) spans[0].textContent = this.formatDollar(derived.minThreshold);
if (rows[1]) rows[1].innerHTML = `<span class="icp-derived-dot" style="background:var(--rflows-status-sustained)"></span>Sufficient (4mo): ${this.formatDollar(derived.sufficientThreshold)}`; if (spans[1]) spans[1].textContent = this.formatDollar(derived.sufficientThreshold);
if (rows[2]) rows[2].innerHTML = `<span class="icp-derived-dot" style="background:var(--rflows-status-thriving)"></span>Overflow (6mo): ${this.formatDollar(derived.maxThreshold)}`; if (spans[2]) spans[2].textContent = this.formatDollar(derived.maxThreshold);
} }
this.redrawNodeOnly(node); this.redrawNodeOnly(node);
this.redrawEdges(); this.redrawEdges();