webui: polish settings layout and button styles

This commit is contained in:
2026-06-08 09:30:37 -06:00
parent 0f7697e9dd
commit 69db0d7fe5
2 changed files with 59 additions and 11 deletions
@@ -105,6 +105,40 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
.kpi div{background:#0f151d;border:1px solid var(--line);border-radius:12px;padding:10px} .kpi div{background:#0f151d;border:1px solid var(--line);border-radius:12px;padding:10px}
.kpi .num{font-size:20px;font-weight:800;margin-top:4px} .kpi .num{font-size:20px;font-weight:800;margin-top:4px}
@media(max-width:760px){.span4,.span6{grid-column:span 12}.big{font-size:36px}.wrap{padding:12px 12px 82px}.kpi{grid-template-columns:1fr}} @media(max-width:760px){.span4,.span6{grid-column:span 12}.big{font-size:36px}.wrap{padding:12px 12px 82px}.kpi{grid-template-columns:1fr}}
/* UI polish v2 */
body{background:radial-gradient(circle at top,#111927 0,#050a0d 48%,#030608 100%)}
.wrap{max-width:1120px}
.card{background:linear-gradient(180deg,#121a25,#0d141d);border-color:#26364b;box-shadow:0 12px 32px rgba(0,0,0,.22)}
.card:hover{border-color:#36506d}
.configGroupHeader{border-bottom:1px solid var(--line);padding-bottom:12px;margin-bottom:16px}
.configGroupTitle,.label{font-size:20px;font-weight:950;color:#f4f8ff;letter-spacing:-.02em}
.configGroupHelp,.sub{font-size:14px;color:#aebbd0;line-height:1.45;max-width:760px}
.row{padding:10px 0;border-bottom:1px solid rgba(255,255,255,.06)}
.row:last-child{border-bottom:0}
input,select,textarea{min-height:42px;margin:3px 0 8px;background:#08111a;border-color:#26384d;color:#f6f8fc;font-size:15px}
input:focus,select:focus,textarea:focus{outline:2px solid #315f9f;border-color:#5d8fd2}
button{min-height:42px;padding:11px 14px;border-radius:12px;font-weight:900;letter-spacing:.01em;border:1px solid #31445d;background:#1d324f;color:#edf5ff}
button:hover{filter:brightness(1.08)}
button:active{transform:translateY(1px)}
button.on,button.save,button[onclick^="save"]{background:linear-gradient(180deg,#1f6b38,#134922);border-color:#2b8a4b;color:#ecfff2}
button.off,button.danger,button[onclick^="reset"],button[onclick^="factory"],button[onclick^="setBmsEnabled(false)"]{background:linear-gradient(180deg,#743039,#4d1d25);border-color:#9b4050;color:#fff1f3}
button.secondary,button[onclick^="toggle"],button[onclick^="connect"],button[onclick^="scan"]{background:linear-gradient(180deg,#28466d,#1b304e);border-color:#3f6598;color:#edf5ff}
.inlineActions{gap:10px}
.inlineActions button{width:100%}
.subtabs{background:rgba(8,13,20,.72);border:1px solid rgba(255,255,255,.06);border-radius:18px;padding:8px;margin-bottom:14px}
.subtabbtn{min-height:38px;padding:9px 14px}
.subtabbtn.active{background:linear-gradient(180deg,#233b5f,#172942);border-color:#4c78b3;color:#fff}
.configWarning{background:#21170c;border-color:#665026;color:#ffe7ad}
.inputHelp{color:#aebbd0;margin-bottom:8px}
.list{gap:8px}
.pill.good{background:#082416;color:#67f0a0;border-color:#1d7747}
.pill.bad{background:#321018;color:#ff9baa;border-color:#8f3446}
@media(min-width:900px){
#config-wifi .card.span12{padding:22px}
#config-wifi .list{gap:10px}
}
</style> </style>
</head> </head>
<body> <body>
@@ -247,10 +281,10 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
<input id="apPasswordInput" placeholder="New AP password" type="password"> <input id="apPasswordInput" placeholder="New AP password" type="password">
<div class="inputHelp">Password must be 8-63 characters. The current password is never displayed.</div> <div class="inputHelp">Password must be 8-63 characters. The current password is never displayed.</div>
<div class="inlineActions"> <div class="inlineActions">
<button onclick="toggleApPassword()">Show / Hide Password</button> <button class="secondary" onclick="toggleApPassword()">Show / Hide Password</button>
<button class="on" onclick="saveApConfig()">Save AP Settings</button> <button class="save" onclick="saveApConfig()">Save AP Settings</button>
</div> </div>
<button class="off" onclick="resetApConfig()">Reset AP to Default</button> <button class="danger" onclick="resetApConfig()">Reset AP to Default</button>
<div class="configWarning">Saving AP settings restarts the access point. Your phone may disconnect and need to reconnect to the new SSID/password. Dashboard auto-migration is planned but not implemented yet.</div> <div class="configWarning">Saving AP settings restarts the access point. Your phone may disconnect and need to reconnect to the new SSID/password. Dashboard auto-migration is planned but not implemented yet.</div>
</div> </div>
</section> </section>
@@ -272,8 +306,8 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
<input id="w3s" placeholder="Network 3 SSID"> <input id="w3s" placeholder="Network 3 SSID">
<input id="w3p" placeholder="Network 3 password" type="password"> <input id="w3p" placeholder="Network 3 password" type="password">
<input id="w3r" placeholder="Network 3 priority" inputmode="numeric"> <input id="w3r" placeholder="Network 3 priority" inputmode="numeric">
<button onclick="saveWifi()">Save WiFi</button> <button class="save" onclick="saveWifi()">Save WiFi</button>
<button onclick="connectWifi()">Connect Now</button> <button class="secondary" onclick="connectWifi()">Connect Now</button>
</div> </div>
</section> </section>
</div> </div>
@@ -289,7 +323,7 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
</div> </div>
</div> </div>
<div class="list" id="relayConfigList"></div> <div class="list" id="relayConfigList"></div>
<button onclick="saveRelayConfig()">Save Relay Names</button> <button class="save" onclick="saveRelayConfig()">Save Relay Names</button>
</section> </section>
</div> </div>
</div> </div>
@@ -304,7 +338,7 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
</div> </div>
</div> </div>
<div class="list"> <div class="list">
<button onclick="scanTemps()">Scan Temp Probes</button> <button class="secondary" onclick="scanTemps()">Scan Temp Probes</button>
<div id="tempScanResults" class="list"></div> <div id="tempScanResults" class="list"></div>
</div> </div>
</section> </section>
@@ -319,7 +353,7 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
<div class="list"> <div class="list">
<input id="tempEnabledCount" placeholder="Enabled sensor count, 0-8" inputmode="numeric"> <input id="tempEnabledCount" placeholder="Enabled sensor count, 0-8" inputmode="numeric">
<div id="tempConfigList" class="list"></div> <div id="tempConfigList" class="list"></div>
<button onclick="saveTempConfig()">Save Temperature Config</button> <button class="save" onclick="saveTempConfig()">Save Temperature Config</button>
</div> </div>
</section> </section>
</div> </div>
@@ -339,7 +373,7 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
<input id="bmsAddressInput" placeholder="BMS BLE address"> <input id="bmsAddressInput" placeholder="BMS BLE address">
<input id="bmsAddressTypeInput" placeholder="Address type: public or random"> <input id="bmsAddressTypeInput" placeholder="Address type: public or random">
<div class="btnrow"> <div class="btnrow">
<button onclick="saveBmsFullConfig()">Save BMS</button> <button class="save" onclick="saveBmsFullConfig()">Save BMS</button>
<button class="off" onclick="setBmsEnabled(false)">Disable BMS</button> <button class="off" onclick="setBmsEnabled(false)">Disable BMS</button>
</div> </div>
<div class="btnrow"> <div class="btnrow">
@@ -361,7 +395,7 @@ input{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px;ba
</div> </div>
</div> </div>
<div class="btnrow"> <div class="btnrow">
<button class="off" onclick="factoryReset()">Factory Reset</button> <button class="danger" onclick="factoryReset()">Factory Reset</button>
</div> </div>
</section> </section>
</div> </div>
+15 -1
View File
@@ -472,7 +472,7 @@ def test_embedded_webui_preserves_config_input_while_polling():
assert 'document.addEventListener("input"' in source assert 'document.addEventListener("input"' in source
assert 'setConfigValue("apSsidInput"' in source assert 'setConfigValue("apSsidInput"' in source
assert "deviceNameInput" in source assert "deviceNameInput" in source
assert 'setConfigValue("bmsNameInput"' in source assert "bmsNameInput" in source
assert 'setConfigValue("tempEnabledCount"' in source assert 'setConfigValue("tempEnabledCount"' in source
@@ -486,3 +486,17 @@ def test_ap_config_can_be_reset_to_defaults():
assert 'api("/config/ap/reset")' in source assert 'api("/config/ap/reset")' in source
assert "Reset AP to Default" in source assert "Reset AP to Default" in source
assert "regenerated password" in source assert "regenerated password" in source
def test_embedded_webui_has_consistent_button_intent_styles():
source = firmware_source()
assert "/* UI polish v2 */" in source
assert "button.save" in source
assert "button.danger" in source
assert "button.secondary" in source
assert "configGroupTitle" in source
assert "linear-gradient" in source
assert 'class="save" onclick="saveApConfig()"' in source
assert 'class="danger" onclick="resetApConfig()"' in source
assert 'class="save" onclick="saveWifi()"' in source