Add mode slider with "Simple," "Advanced," and "Expert" modes; dynamically hide/show UI elements based on selected mode.

This commit is contained in:
Kai Börnert
2026-04-28 17:19:34 +02:00
parent 9cd20cd56b
commit 30bcdf6f3b
9 changed files with 215 additions and 43 deletions

View File

@@ -10,10 +10,10 @@
<div class="subtitle">Hardware:</div> <div class="subtitle">Hardware:</div>
<div class="flexcontainer"> <div class="flexcontainer">
<div class="boardkey">BoardRevision</div> <div class="boardkey">BoardRevision</div>
<select class="boardvalue" id="hardware_board_value"> <select class="boardvalue hidden-mode-advanced" id="hardware_board_value">
</select> </select>
</div> </div>
<div class="flexcontainer"> <div class="flexcontainer hidden-mode-advanced">
<div class="boardkey">BatteryMonitor</div> <div class="boardkey">BatteryMonitor</div>
<select class="boardvalue" id="hardware_battery_value"> <select class="boardvalue" id="hardware_battery_value">
</select> </select>

View File

@@ -137,11 +137,157 @@
font-weight: bold; font-weight: bold;
} }
.mode-slider-container {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
padding: 8px 0;
flex-wrap: wrap;
}
.mode-label {
font-weight: bold;
font-size: 0.85em;
min-width: 55px;
text-align: center;
}
.mode-slider {
-webkit-appearance: none;
appearance: none;
width: 200px;
height: 8px;
border-radius: 4px;
outline: none;
cursor: pointer;
}
.mode-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
cursor: pointer;
border: 2px solid white;
}
.mode-slider::-moz-range-thumb {
width: 20px;
height: 20px;
border-radius: 50%;
cursor: pointer;
border: 2px solid white;
}
.mode-simple .mode-slider {
background: linear-gradient(to right, #28a745, #28a745);
}
.mode-simple .mode-slider::-webkit-slider-thumb {
background: #28a745;
}
.mode-simple .mode-slider::-moz-range-thumb {
background: #28a745;
}
.mode-advanced .mode-slider {
background: linear-gradient(to right, #28a745, #ffc107);
}
.mode-advanced .mode-slider::-webkit-slider-thumb {
background: #ffc107;
}
.mode-advanced .mode-slider::-moz-range-thumb {
background: #ffc107;
}
.mode-expert .mode-slider {
background: linear-gradient(to right, #28a745, #ffc107, #dc3545);
}
.mode-expert .mode-slider::-webkit-slider-thumb {
background: #dc3545;
}
.mode-expert .mode-slider::-moz-range-thumb {
background: #dc3545;
}
.mode-simple .mode-label {
color: #28a745;
}
.mode-advanced .mode-label {
color: #ffc107;
}
.mode-expert .mode-label {
color: #dc3545;
}
.mode-label-mode {
font-size: 0.9em;
font-weight: bold;
min-width: 60px;
}
.mode-simple .mode-label-mode {
color: #28a745;
}
.mode-advanced .mode-label-mode {
color: #ffc107;
}
.mode-expert .mode-label-mode {
color: #dc3545;
}
.mode-dot {
width: 8px;
height: 8px;
border-radius: 50%;
display: inline-block;
margin-right: 4px;
vertical-align: middle;
}
.mode-simple .mode-dot {
background: #28a745;
}
.mode-advanced .mode-dot {
background: #ffc107;
}
.mode-expert .mode-dot {
background: #dc3545;
}
.hidden-mode {
display: none !important;
}
.mode-simple .hidden-mode-simple,
.mode-advanced .hidden-mode-simple,
.mode-expert .hidden-mode-simple {
display: none !important;
}
.mode-advanced .hidden-mode-advanced,
.mode-expert .hidden-mode-advanced {
display: none !important;
}
.mode-expert .hidden-mode-expert {
display: none !important;
}
</style> </style>
<div class="container-xl"> <div class="container-xl">
<div class="mode-slider-container mode-simple" id="modeSliderContainer">
<span class="mode-dot"></span>
<span class="mode-label">Simple</span>
<input type="range" class="mode-slider" id="configModeSlider" min="0" max="2" value="0" step="1">
<span class="mode-label">Expert</span>
<span class="mode-label-mode" id="modeLabel">Simple</span>
</div>
<div style="display:flex; flex-wrap: wrap;"> <div style="display:flex; flex-wrap: wrap;">
<div id="hardwareview" class="subcontainer"></div> <div id="hardwareview" class="subcontainer"></div>
</div> </div>

View File

@@ -560,6 +560,24 @@ export class Controller {
readonly can_power: HTMLInputElement; readonly can_power: HTMLInputElement;
readonly auto_refresh_moisture_sensors: HTMLInputElement; readonly auto_refresh_moisture_sensors: HTMLInputElement;
private auto_refresh_timer: NodeJS.Timeout | undefined; private auto_refresh_timer: NodeJS.Timeout | undefined;
readonly configModeSlider: HTMLInputElement;
readonly modeSliderContainer: HTMLDivElement;
readonly modeLabel: HTMLElement;
setMode(mode: number) {
const container = this.modeSliderContainer;
container.classList.remove('mode-simple', 'mode-advanced', 'mode-expert');
if (mode === 0) {
container.classList.add('mode-simple');
this.modeLabel.textContent = 'Simple';
} else if (mode === 1) {
container.classList.add('mode-advanced');
this.modeLabel.textContent = 'Advanced';
} else {
container.classList.add('mode-expert');
this.modeLabel.textContent = 'Expert';
}
}
constructor() { constructor() {
this.timeView = new TimeView(this) this.timeView = new TimeView(this)
@@ -606,6 +624,14 @@ export class Controller {
this.autoRefreshLoop() this.autoRefreshLoop()
} }
} }
this.configModeSlider = document.getElementById("configModeSlider") as HTMLInputElement;
this.modeSliderContainer = document.getElementById("modeSliderContainer") as HTMLDivElement;
this.modeLabel = document.getElementById("modeLabel") as HTMLElement;
this.configModeSlider.oninput = () => {
this.setMode(parseInt(this.configModeSlider.value));
};
this.setMode(0);
} }
private async autoRefreshLoop() { private async autoRefreshLoop() {

View File

@@ -53,7 +53,7 @@
<input class="basicnetworkvalue" type="text" id="password"> <input class="basicnetworkvalue" type="text" id="password">
</div> </div>
</div> </div>
<div class="subcontainer"> <div class="subcontainer hidden-mode-advanced">
<div class="flexcontainer"> <div class="flexcontainer">
<div class="subtitle"> <div class="subtitle">
Mqtt Reporting Mqtt Reporting

View File

@@ -28,21 +28,21 @@
<div class="lightkey">Light only when dark</div> <div class="lightkey">Light only when dark</div>
<input class="lightcheckbox" type="checkbox" id="night_lamp_only_when_dark"> <input class="lightcheckbox" type="checkbox" id="night_lamp_only_when_dark">
</div> </div>
<div class="flexcontainer"> <div class="flexcontainer hidden-mode-advanced">
<div class="lightkey">Start</div> <div class="lightkey">Start</div>
<select class="lightnumberbox" type="time" id="night_lamp_time_start"> <select class="lightnumberbox" type="time" id="night_lamp_time_start">
</select> </select>
</div> </div>
<div class="flexcontainer"> <div class="flexcontainer hidden-mode-advanced">
<div class="lightkey">Stop</div> <div class="lightkey">Stop</div>
<select class="lightnumberbox" type="time" id="night_lamp_time_end"> <select class="lightnumberbox" type="time" id="night_lamp_time_end">
</select> </select>
</div> </div>
<div class="flexcontainer"> <div class="flexcontainer hidden-mode-expert">
<div class="lightkey">Disable if Battery below %</div> <div class="lightkey">Disable if Battery below %</div>
<input class="lightcheckbox" type="number" id="night_lamp_soc_low" min="0" max="100"> <input class="lightcheckbox" type="number" id="night_lamp_soc_low" min="0" max="100">
</div> </div>
<div class="flexcontainer"> <div class="flexcontainer hidden-mode-expert">
<div class="lightkey">Reenable if Battery higher %</div> <div class="lightkey">Reenable if Battery higher %</div>
<input class="lightcheckbox" type="number" id="night_lamp_soc_restore" min="0" max="100"> <input class="lightcheckbox" type="number" id="night_lamp_soc_restore" min="0" max="100">
</div> </div>

View File

@@ -43,7 +43,7 @@
<span class="otakey">State1:</span> <span class="otakey">State1:</span>
<span class="otavalue" id="firmware_state1"></span> <span class="otavalue" id="firmware_state1"></span>
</div> </div>
<div class="flexcontainer"> <div class="flexcontainer hidden-mode-advanced">
<form class="otaform" id="upload_form" method="post"> <form class="otaform" id="upload_form" method="post">
<input class="otachooser" type="file" name="file1" id="firmware_file"><br> <input class="otachooser" type="file" name="file1" id="firmware_file"><br>
</form> </form>
@@ -73,5 +73,5 @@
<div class="display:flex"> <div class="display:flex">
<button style="margin-left: 16px; margin-top: 8px;" class="col-6" type="button" id="test">Self-Test</button> <button style="margin-left: 16px; margin-top: 8px;" class="col-6 hidden-mode-advanced" type="button" id="test">Self-Test</button>
</div> </div>

View File

@@ -37,7 +37,7 @@
<div> <div>
<div class="subtitle" <div class="subtitle"
id="plant_${plantId}_header"> id="plant_${plantId}_header">
Plant ${plantId} Plant ${plantId}
</div> </div>
<div class="flexcontainer"> <div class="flexcontainer">
@@ -91,11 +91,11 @@
<input class="plantvalue" id="plant_${plantId}_max_consecutive_pump_count" type="number" min="1" max="50" <input class="plantvalue" id="plant_${plantId}_max_consecutive_pump_count" type="number" min="1" max="50"
placeholder="10"> placeholder="10">
</div> </div>
<div class="flexcontainer plantSensorEnabledOnly_${plantId}"> <div class="flexcontainer plantSensorEnabledOnly_${plantId} hidden-mode-advanced">
<div class="plantkey">Min Frequency Override</div> <div class="plantkey">Min Frequency Override</div>
<input class="plantvalue" id="plant_${plantId}_min_frequency" type="number" min="1000" max="25000"> <input class="plantvalue" id="plant_${plantId}_min_frequency" type="number" min="1000" max="25000">
</div> </div>
<div class="flexcontainer plantSensorEnabledOnly_${plantId}"> <div class="flexcontainer plantSensorEnabledOnly_${plantId} hidden-mode-advanced">
<div class="plantkey">Max Frequency Override</div> <div class="plantkey">Max Frequency Override</div>
<input class="plantvalue" id="plant_${plantId}_max_frequency" type="number" min="1000" max="25000"> <input class="plantvalue" id="plant_${plantId}_max_frequency" type="number" min="1000" max="25000">
</div> </div>
@@ -104,71 +104,71 @@
<div class="flexcontainer plantPumpEnabledOnly_${plantId}"> <div class="flexcontainer plantPumpEnabledOnly_${plantId}">
<h2 class="plantkey">Current config:</h2> <h2 class="plantkey">Current config:</h2>
</div> </div>
<div class="flexcontainer plantPumpEnabledOnly_${plantId}"> <div class="flexcontainer plantPumpEnabledOnly_${plantId} hidden-mode-advanced">
<div class="plantkey">Min current</div> <div class="plantkey">Min current</div>
<input class="plantvalue" id="plant_${plantId}_min_pump_current_ma" type="number" min="0" max="4500"> <input class="plantvalue" id="plant_${plantId}_min_pump_current_ma" type="number" min="0" max="4500">
</div> </div>
<div class="flexcontainer plantPumpEnabledOnly_${plantId}"> <div class="flexcontainer plantPumpEnabledOnly_${plantId} hidden-mode-advanced">
<div class="plantkey">Max current</div> <div class="plantkey">Max current</div>
<input class="plantvalue" id="plant_${plantId}_max_pump_current_ma" type="number" min="0" max="4500"> <input class="plantvalue" id="plant_${plantId}_max_pump_current_ma" type="number" min="0" max="4500">
</div> </div>
<div class="flexcontainer plantPumpEnabledOnly_${plantId}"> <div class="flexcontainer plantPumpEnabledOnly_${plantId} hidden-mode-advanced">
<div class="plantkey">Ignore current sensor error</div> <div class="plantkey">Ignore current sensor error</div>
<input class="plantcheckbox" id="plant_${plantId}_ignore_current_error" type="checkbox"> <input class="plantcheckbox" id="plant_${plantId}_ignore_current_error" type="checkbox">
</div> </div>
<div class="flexcontainer plantPumpEnabledOnly_${plantId}"> <div class="flexcontainer plantPumpEnabledOnly_${plantId} hidden-mode-advanced">
<button class="subtitle" id="plant_${plantId}_test">Test Pump</button> <button class="subtitle" id="plant_${plantId}_test">Test Pump</button>
</div> </div>
<div class="flexcontainer plantSensorEnabledOnly_${plantId}"> <div class="flexcontainer plantSensorEnabledOnly_${plantId} hidden-mode-advanced">
<div class="subtitle">Live:</div> <div class="subtitle">Live:</div>
</div> </div>
<div class="flexcontainer plantSensorEnabledOnly_${plantId}"> <div class="flexcontainer plantSensorEnabledOnly_${plantId} hidden-mode-advanced">
<button class="subtitle" id="plant_${plantId}_test_sensor_a">Identify Sensor A</button> <button class="subtitle" id="plant_${plantId}_test_sensor_a">Identify Sensor A</button>
<button class="subtitle" id="plant_${plantId}_test_sensor_b">Identify Sensor B</button> <button class="subtitle" id="plant_${plantId}_test_sensor_b">Identify Sensor B</button>
</div> </div>
<div class="flexcontainer plantSensorEnabledOnly_${plantId}"> <div class="flexcontainer plantSensorEnabledOnly_${plantId} hidden-mode-advanced">
<span class="plantsensorkey">Sensor A:</span> <span class="plantsensorkey">Sensor A:</span>
<span class="plantsensorvalue" id="plant_${plantId}_moisture_a">not measured</span> <span class="plantsensorvalue" id="plant_${plantId}_moisture_a">not measured</span>
</div> </div>
<div class="flexcontainer plantSensorEnabledOnly_${plantId}"> <div class="flexcontainer plantSensorEnabledOnly_${plantId} hidden-mode-advanced">
<span class="plantsensorkey">Sensor A FW:</span> <span class="plantsensorkey">Sensor A FW:</span>
<span class="plantsensorvalue" id="plant_${plantId}_sensor_a_fw_build">unknown</span> <span class="plantsensorvalue" id="plant_${plantId}_sensor_a_fw_build">unknown</span>
</div> </div>
<div class="flexcontainer plantSensorEnabledOnly_${plantId}"> <div class="flexcontainer plantSensorEnabledOnly_${plantId} hidden-mode-advanced">
<div class="plantsensorkey">Sensor B:</div> <div class="plantsensorkey">Sensor B:</div>
<span class="plantsensorvalue" id="plant_${plantId}_moisture_b">not measured</span> <span class="plantsensorvalue" id="plant_${plantId}_moisture_b">not measured</span>
</div> </div>
<div class="flexcontainer plantSensorEnabledOnly_${plantId}"> <div class="flexcontainer plantSensorEnabledOnly_${plantId} hidden-mode-advanced">
<span class="plantsensorkey">Sensor B FW:</span> <span class="plantsensorkey">Sensor B FW:</span>
<span class="plantsensorvalue" id="plant_${plantId}_sensor_b_fw_build">unknown</span> <span class="plantsensorvalue" id="plant_${plantId}_sensor_b_fw_build">unknown</span>
</div> </div>
<div class="flexcontainer plantPumpEnabledOnly_${plantId}"> <div class="flexcontainer plantPumpEnabledOnly_${plantId} hidden-mode-advanced">
<div class="plantsensorkey">Max Current</div> <div class="plantsensorkey">Max Current</div>
<span class="plantsensorvalue" id="plant_${plantId}_pump_test_current_max">not_tested</span> <span class="plantsensorvalue" id="plant_${plantId}_pump_test_current_max">not_tested</span>
</div> </div>
<div class="flexcontainer plantPumpEnabledOnly_${plantId}"> <div class="flexcontainer plantPumpEnabledOnly_${plantId} hidden-mode-advanced">
<div class="plantsensorkey">Min Current</div> <div class="plantsensorkey">Min Current</div>
<span class="plantsensorvalue" id="plant_${plantId}_pump_test_current_min">not_tested</span> <span class="plantsensorvalue" id="plant_${plantId}_pump_test_current_min">not_tested</span>
</div> </div>
<div class="flexcontainer plantPumpEnabledOnly_${plantId}"> <div class="flexcontainer plantPumpEnabledOnly_${plantId} hidden-mode-advanced">
<div class="plantsensorkey">Average</div> <div class="plantsensorkey">Average</div>
<span class="plantsensorvalue" id="plant_${plantId}_pump_test_current_average">not_tested</span> <span class="plantsensorvalue" id="plant_${plantId}_pump_test_current_average">not_tested</span>
</div> </div>
<div class="flexcontainer plantPumpEnabledOnly_${plantId}"> <div class="flexcontainer plantPumpEnabledOnly_${plantId} hidden-mode-advanced">
<div class="plantsensorkey">Pump Time</div> <div class="plantsensorkey">Pump Time</div>
<span class="plantsensorvalue" id="plant_${plantId}_pump_test_pump_time">not_tested</span> <span class="plantsensorvalue" id="plant_${plantId}_pump_test_pump_time">not_tested</span>
</div> </div>
<div class="flexcontainer plantPumpEnabledOnly_${plantId}"> <div class="flexcontainer plantPumpEnabledOnly_${plantId} hidden-mode-advanced">
<div class="plantsensorkey">Flow ml</div> <div class="plantsensorkey">Flow ml</div>
<span class="plantsensorvalue" id="plant_${plantId}_pump_test_flow_ml">not_tested</span> <span class="plantsensorvalue" id="plant_${plantId}_pump_test_flow_ml">not_tested</span>
</div> </div>
<div class="flexcontainer plantPumpEnabledOnly_${plantId}"> <div class="flexcontainer plantPumpEnabledOnly_${plantId} hidden-mode-advanced">
<div class="plantsensorkey">Flow raw</div> <div class="plantsensorkey">Flow raw</div>
<span class="plantsensorvalue" id="plant_${plantId}_pump_test_flow_raw">not_tested</span> <span class="plantsensorvalue" id="plant_${plantId}_pump_test_flow_raw">not_tested</span>
</div> </div>
</div> </div>

View File

@@ -27,14 +27,14 @@
</style> </style>
<button class="submitbutton" id="submit">Submit</button> <button class="submitbutton" id="submit">Submit</button>
<br> <br>
<button id="showJson">Show Json</button> <button class="hidden-mode-advanced" id="showJson">Show Json</button>
<div id="rawdata" class="flexcontainer" style="display: none;"> <div id="rawdata" class="flexcontainer hidden-mode-advanced" style="display: none;">
<div class="submitarea" id="json" contenteditable="true"></div> <div class="submitarea" id="json" contenteditable="true"></div>
<div class="submitarea" id="backupjson">backup will be here</div> <div class="submitarea" id="backupjson">backup will be here</div>
</div> </div>
<div>BackupStatus:</div> <div>BackupStatus:</div>
<div id="backuptimestamp"></div> <div id="backuptimestamp"></div>
<div id="backupsize"></div> <div id="backupsize"></div>
<button id="backup">Backup</button> <button class="hidden-mode-advanced" id="backup">Backup</button>
<button id="restorebackup">Restore</button> <button class="hidden-mode-advanced" id="restorebackup">Restore</button>
<div id="submit_status"></div> <div id="submit_status"></div>

View File

@@ -20,7 +20,7 @@
<span style="flex-grow: 1; text-align: center; font-weight: bold;"> <span style="flex-grow: 1; text-align: center; font-weight: bold;">
Tank: Tank:
</span> </span>
<input id="tankview_auto_refresh" type="checkbox"> <input id="tankview_auto_refresh" type="checkbox">
</div> </div>
<div class="flexcontainer"> <div class="flexcontainer">
<span class="tankkey">Enable Tank Sensor</span> <span class="tankkey">Enable Tank Sensor</span>
@@ -32,23 +32,23 @@
</div> </div>
<div class="flexcontainer"> <div class="flexcontainer hidden-mode-advanced">
<div class="tankkey">Useable ml full% to empty%</div> <div class="tankkey">Useable ml full% to empty%</div>
<input class="tankvalue" type="number" min="2" max="500000" id="tank_useable_ml"> <input class="tankvalue" type="number" min="2" max="500000" id="tank_useable_ml">
</div> </div>
<div class="flexcontainer"> <div class="flexcontainer hidden-mode-advanced">
<div class="tankkey">Warn below %</div> <div class="tankkey">Warn below %</div>
<input class="tankvalue" type="number" min="1" max="500000" id="tank_warn_percent"> <input class="tankvalue" type="number" min="1" max="500000" id="tank_warn_percent">
</div> </div>
<div class="flexcontainer"> <div class="flexcontainer hidden-mode-advanced">
<div class="tankkey">Empty at %</div> <div class="tankkey">Empty at %</div>
<input class="tankvalue" type="number" min="0" max="100" id="tank_empty_percent"> <input class="tankvalue" type="number" min="0" max="100" id="tank_empty_percent">
</div> </div>
<div class="flexcontainer"> <div class="flexcontainer hidden-mode-advanced">
<div class="tankkey">Full at %</div> <div class="tankkey">Full at %</div>
<input class="tankvalue" type="number" min="0" max="100" id="tank_full_percent"> <input class="tankvalue" type="number" min="0" max="100" id="tank_full_percent">
</div> </div>
<div class="flexcontainer"> <div class="flexcontainer hidden-mode-expert">
<div class="tankkey">Flow Sensor ml per pulse</div> <div class="tankkey">Flow Sensor ml per pulse</div>
<input class="tankvalue" type="number" min="0" max="1000" step="0.01" id="ml_per_pulse"> <input class="tankvalue" type="number" min="0" max="1000" step="0.01" id="ml_per_pulse">
</div> </div>
@@ -86,4 +86,4 @@
<div class="flexcontainer"> <div class="flexcontainer">
<div class="tankkey">Warn Level</div> <div class="tankkey">Warn Level</div>
<label class="tankvalue" id="tank_measure_warnlevel"></label> <label class="tankvalue" id="tank_measure_warnlevel"></label>
</div> </div>