From 61605fb7f2ee0d0c23a95d0df357515652dd04e1 Mon Sep 17 00:00:00 2001 From: Richard Sauer Date: Thu, 9 Apr 2026 13:32:17 +1000 Subject: [PATCH] Custom card colors (text/active/inactive), smart automation toggle logic --- templates/editor.html | 88 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 15 deletions(-) diff --git a/templates/editor.html b/templates/editor.html index 6e1c651..bf7e547 100644 --- a/templates/editor.html +++ b/templates/editor.html @@ -466,6 +466,14 @@ function createCardEl(c) { const s = simState[c.id] || {on: false, value: 0}; if (c.type !== 'temp' && s.on) el.classList.add('on'); + // Apply custom colors + if (c.type !== 'temp') { + const onColor = c.activeColor || (c.type === 'burner' ? 'var(--amber)' : 'var(--green)'); + const offColor = c.inactiveColor || 'var(--red)'; + el.style.background = s.on ? onColor : offColor; + } + if (c.textColor) el.style.color = c.textColor; + // Drag handle (edit mode) el.innerHTML = ``; @@ -779,14 +787,28 @@ function editCardProps(id) {
- + + + +
+
+ + + +
+
+ + + +
+
+ -
- + ${card.fontSize||18}px
${extraFields} @@ -816,6 +838,9 @@ function saveCardProps(id) { card.width = document.getElementById('prop-width').value; const color = document.getElementById('prop-color').value; card.color = color || null; + card.textColor = document.getElementById('prop-textcolor').value || null; + card.activeColor = document.getElementById('prop-activecolor').value || null; + card.inactiveColor = document.getElementById('prop-inactivecolor').value || null; card.fontSize = parseInt(document.getElementById('prop-fontsize').value) || 18; const spEl = document.getElementById('prop-sp'); @@ -850,21 +875,54 @@ function toggleSim(id) { } } - // If this is an automation card, activate/deactivate all its rules - if (card && card.type === 'automation' && card.rules) { - card.rules.forEach(r => { - if (!r.target) return; - if (!simState[r.target]) simState[r.target] = {on: false, value: 0}; - if (simState[id].on) { - // Activating: apply all rules + // Automation logic: activating one deactivates others, but shared outputs stay on + if (card && card.type === 'automation') { + if (simState[id].on && card.rules) { + // Collect all targets this automation activates + const myTargets = new Set(); + card.rules.forEach(r => { if (r.target) myTargets.add(r.target); }); + + // Deactivate other automation cards, but track what they had on + const allAutoCards = []; + layout.pages.forEach(p => p.cards.forEach(c => { + if (c.type === 'automation' && c.id !== id) allAutoCards.push(c); + })); + + allAutoCards.forEach(ac => { + if (simState[ac.id] && simState[ac.id].on) { + // Turn off this automation + simState[ac.id].on = false; + // Turn off its outputs ONLY if not shared with the new automation + (ac.rules || []).forEach(r => { + if (r.target && !myTargets.has(r.target)) { + if (simState[r.target] && r.action !== 'off') simState[r.target].on = false; + } + }); + } + }); + + // Now apply this automation's rules + card.rules.forEach(r => { + if (!r.target) return; + if (!simState[r.target]) simState[r.target] = {on: false, value: 0}; if (r.action === 'on') simState[r.target].on = true; else if (r.action === 'off') simState[r.target].on = false; else if (r.action === 'set') { simState[r.target].on = true; simState[r.target].value = r.value || 0; } - } else { - // Deactivating: turn everything off - if (r.action !== 'off') simState[r.target].on = false; - } - }); + }); + } else if (!simState[id].on && card.rules) { + // Deactivating: turn off outputs that no other active automation needs + const otherActiveTargets = new Set(); + layout.pages.forEach(p => p.cards.forEach(c => { + if (c.type === 'automation' && c.id !== id && simState[c.id] && simState[c.id].on) { + (c.rules || []).forEach(r => { if (r.target) otherActiveTargets.add(r.target); }); + } + })); + card.rules.forEach(r => { + if (r.target && !otherActiveTargets.has(r.target) && r.action !== 'off') { + if (simState[r.target]) simState[r.target].on = false; + } + }); + } } renderCards();