Add configurable water-softener diagram to Dashboard
Per-asset diagram_config (JSONB) maps live MQTT field_keys to brine/resin tank roles, editable on the Assets page with dropdowns populated from that asset's actual telemetry. Dashboard renders brine + 1-2 resin tanks with color-coded fill levels, an "in service" tank indicator, and an animated flow/regen indicator when regeneration is active.
This commit is contained in:
parent
eca07750d2
commit
4f048a9629
9 changed files with 4779 additions and 11 deletions
|
|
@ -209,6 +209,111 @@ html, body, #root { height: 100%; margin: 0; font-size: 14px; }
|
|||
.asset-field-key { color: var(--text-mid); }
|
||||
.asset-field-value { font-weight: 600; color: var(--text-dark); }
|
||||
|
||||
/* ── Water softener diagram ────────────────────────────────── */
|
||||
.softener-diagram-empty {
|
||||
font-size: 12px;
|
||||
color: var(--text-mid);
|
||||
background: var(--body-bg);
|
||||
border: 1px dashed var(--card-border);
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.softener-diagram { margin-bottom: 12px; }
|
||||
.softener-regen-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 11.5px;
|
||||
font-weight: 600;
|
||||
color: var(--gold);
|
||||
background: rgba(201,168,76,.12);
|
||||
border-radius: 6px;
|
||||
padding: 4px 8px;
|
||||
margin-bottom: 8px;
|
||||
width: fit-content;
|
||||
}
|
||||
.softener-diagram-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.softener-flow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--card-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.softener-flow svg { margin-left: -6px; }
|
||||
.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(3) { animation-delay: .3s; }
|
||||
@keyframes softener-flow-pulse {
|
||||
0%, 100% { opacity: .25; }
|
||||
50% { opacity: 1; }
|
||||
}
|
||||
|
||||
.softener-tank {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 76px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.softener-tank-standby { opacity: .5; }
|
||||
.softener-tank-active .softener-tank-shell { border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold); }
|
||||
.softener-badge {
|
||||
position: absolute;
|
||||
top: -9px;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
background: var(--gold);
|
||||
color: var(--navy);
|
||||
font-size: 9px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .02em;
|
||||
border-radius: 20px;
|
||||
padding: 2px 7px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.softener-badge-regen { background: var(--app-primary); color: #fff; }
|
||||
.softener-tank-shell {
|
||||
position: relative;
|
||||
width: 56px;
|
||||
height: 90px;
|
||||
border: 2px solid var(--card-border);
|
||||
border-radius: 10px 10px 6px 6px;
|
||||
background: var(--body-bg);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.softener-tank-fill {
|
||||
position: absolute;
|
||||
bottom: 0; left: 0; right: 0;
|
||||
transition: height .5s ease;
|
||||
}
|
||||
.softener-fill-ok { background: var(--sev-ok); }
|
||||
.softener-fill-warning { background: var(--sev-warning); }
|
||||
.softener-fill-critical { background: var(--sev-critical); }
|
||||
.softener-fill-unknown { background: var(--card-border); height: 0 !important; }
|
||||
.softener-tank-pct {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: var(--text-dark);
|
||||
text-shadow: 0 1px 2px rgba(255,255,255,.6);
|
||||
}
|
||||
.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); }
|
||||
|
||||
/* ── Badges ────────────────────────────────────────────────── */
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue