Trim flow chevrons to fit one row, add water-passing indicator
Regen flow indicators now show 2 chevrons instead of 3 so the diagram row fits without wrapping on narrow cards. Added a pulsing vertical chevron stack under each tank's % reading, shown when that tank is actually in-service and passing water (not regenerating).
This commit is contained in:
parent
0ab98d3a3c
commit
ff145957fc
2 changed files with 30 additions and 5 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import { RefreshCw, ChevronsRight, ChevronsLeft } from 'lucide-react'
|
import { RefreshCw, ChevronsRight, ChevronsLeft, ChevronsDown } from 'lucide-react'
|
||||||
import type { AssetStatus, TelemetryField } from '../types'
|
import type { AssetStatus, TelemetryField } from '../types'
|
||||||
|
|
||||||
function fieldByKey(latest: TelemetryField[], key: string | null): TelemetryField | undefined {
|
function fieldByKey(latest: TelemetryField[], key: string | null): TelemetryField | undefined {
|
||||||
|
|
@ -44,6 +44,10 @@ function Tank({ label, pct, valueLabel, variant, regenerating }: {
|
||||||
regenerating: boolean
|
regenerating: boolean
|
||||||
}) {
|
}) {
|
||||||
const clamped = pct === null ? 0 : Math.max(0, Math.min(100, pct))
|
const clamped = pct === null ? 0 : Math.max(0, Math.min(100, pct))
|
||||||
|
// Water is passing through whichever tank is actually in service right now
|
||||||
|
// (or the single tank, when it's not offline regenerating) — shown as
|
||||||
|
// pulsing down-chevrons under the % reading.
|
||||||
|
const passingWater = !regenerating && variant !== 'standby'
|
||||||
return (
|
return (
|
||||||
<div className={`softener-tank softener-tank-${variant}`}>
|
<div className={`softener-tank softener-tank-${variant}`}>
|
||||||
{variant === 'active' && (
|
{variant === 'active' && (
|
||||||
|
|
@ -54,7 +58,15 @@ function Tank({ label, pct, valueLabel, variant, regenerating }: {
|
||||||
)}
|
)}
|
||||||
<div className="softener-tank-shell">
|
<div className="softener-tank-shell">
|
||||||
<div className={`softener-tank-fill ${levelClass(pct)}`} style={{ height: `${clamped}%` }} />
|
<div className={`softener-tank-fill ${levelClass(pct)}`} style={{ height: `${clamped}%` }} />
|
||||||
<div className="softener-tank-pct">{pct === null ? '—' : `${Math.round(pct)}%`}</div>
|
<div className="softener-tank-content">
|
||||||
|
<div className="softener-tank-pct">{pct === null ? '—' : `${Math.round(pct)}%`}</div>
|
||||||
|
{passingWater && (
|
||||||
|
<div className="softener-tank-water" aria-hidden="true">
|
||||||
|
<ChevronsDown size={11} strokeWidth={2} />
|
||||||
|
<ChevronsDown size={11} strokeWidth={2} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="softener-tank-label">{label}</div>
|
<div className="softener-tank-label">{label}</div>
|
||||||
<div className="softener-tank-value">{valueLabel}</div>
|
<div className="softener-tank-value">{valueLabel}</div>
|
||||||
|
|
@ -105,7 +117,6 @@ export default function WaterSoftenerDiagram({ asset }: { asset: AssetStatus })
|
||||||
<div className={`softener-flow softener-flow-${direction} ${active ? 'softener-flow-active' : ''}`} aria-hidden="true">
|
<div className={`softener-flow softener-flow-${direction} ${active ? 'softener-flow-active' : ''}`} aria-hidden="true">
|
||||||
<Icon size={16} strokeWidth={2} />
|
<Icon size={16} strokeWidth={2} />
|
||||||
<Icon size={16} strokeWidth={2} />
|
<Icon size={16} strokeWidth={2} />
|
||||||
<Icon size={16} strokeWidth={2} />
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -249,7 +249,6 @@ html, body, #root { height: 100%; margin: 0; font-size: 14px; }
|
||||||
.softener-flow-left svg { margin-right: -6px; }
|
.softener-flow-left svg { margin-right: -6px; }
|
||||||
.softener-flow-active svg { color: var(--app-primary); animation: softener-flow-pulse 1.1s ease-in-out infinite; }
|
.softener-flow-active svg { color: var(--app-primary); animation: softener-flow-pulse 1.1s ease-in-out infinite; }
|
||||||
.softener-flow-active svg:nth-child(2) { animation-delay: .15s; }
|
.softener-flow-active svg:nth-child(2) { animation-delay: .15s; }
|
||||||
.softener-flow-active svg:nth-child(3) { animation-delay: .3s; }
|
|
||||||
@keyframes softener-flow-pulse {
|
@keyframes softener-flow-pulse {
|
||||||
0%, 100% { opacity: .25; }
|
0%, 100% { opacity: .25; }
|
||||||
50% { opacity: 1; }
|
50% { opacity: 1; }
|
||||||
|
|
@ -304,14 +303,29 @@ html, body, #root { height: 100%; margin: 0; font-size: 14px; }
|
||||||
.softener-fill-warning { background: var(--sev-warning); }
|
.softener-fill-warning { background: var(--sev-warning); }
|
||||||
.softener-fill-critical { background: var(--sev-critical); }
|
.softener-fill-critical { background: var(--sev-critical); }
|
||||||
.softener-fill-unknown { background: var(--card-border); height: 0 !important; }
|
.softener-fill-unknown { background: var(--card-border); height: 0 !important; }
|
||||||
.softener-tank-pct {
|
.softener-tank-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
.softener-tank-pct {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-dark);
|
color: var(--text-dark);
|
||||||
text-shadow: 0 1px 2px rgba(255,255,255,.6);
|
text-shadow: 0 1px 2px rgba(255,255,255,.6);
|
||||||
}
|
}
|
||||||
|
.softener-tank-water {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--app-primary);
|
||||||
|
filter: drop-shadow(0 1px 1px rgba(255,255,255,.6));
|
||||||
|
}
|
||||||
|
.softener-tank-water svg { margin-top: -4px; animation: softener-flow-pulse 1.1s ease-in-out infinite; }
|
||||||
|
.softener-tank-water svg:nth-child(2) { animation-delay: .2s; }
|
||||||
.softener-tank-label { font-size: 11px; font-weight: 600; color: var(--text-dark); margin-top: 6px; }
|
.softener-tank-label { font-size: 11px; font-weight: 600; color: var(--text-dark); margin-top: 6px; }
|
||||||
.softener-tank-value { font-size: 10px; color: var(--text-mid); }
|
.softener-tank-value { font-size: 10px; color: var(--text-mid); }
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue