3 Commits

Author SHA1 Message Date
Ian Renton
6ed0eed10b Web UI options faff 2026-01-30 20:56:18 +00:00
Ian Renton
221fade44b Merge remote-tracking branch 'origin/main' 2026-01-30 17:13:10 +00:00
Ian Renton
721d345332 Allow users to return to "Automatic" colour scheme. #102 2026-01-30 17:12:57 +00:00
19 changed files with 153 additions and 123 deletions

View File

@@ -34,20 +34,20 @@ These are supplied with the URL to the page you want to embed, for example for a
The supported parameters are as follows. Generally these match the equivalent parameters in the real Spothole API, where a mapping exists. The supported parameters are as follows. Generally these match the equivalent parameters in the real Spothole API, where a mapping exists.
| Name | Allowed Values | Default | Example | Description | | Name | Allowed Values | Default | Example | Description |
|----------------|-----------------------|---------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------| |----------------|-------------------------|---------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `embedded` | `true`, `false` | `false` | `?embedded=true` | Enables embedded mode. | | `embedded` | `true`, `false` | `false` | `?embedded=true` | Enables embedded mode. |
| `dark-mode` | `true`, `false` | `false` | `?dark-mode=true` | Enables dark mode. | | `color-scheme` | `light`, `dark`, `auto` | `auto` | `?color-scheme=dark` | Forces light or dark mode in preference to the operating system default. |
| `time-zone` | `UTC`, `local` | `UTC` | `?time-zone=local` | Sets times to be in UTC or local time. | | `time-zone` | `UTC`, `local` | `UTC` | `?time-zone=local` | Sets times to be in UTC or local time. |
| `limit` | 10, 25, 50, 100 | 50 | `?limit=50` | Sets the number of spots that will be displayed on the main spots page | | `limit` | 10, 25, 50, 100 | 50 | `?limit=50` | Sets the number of spots that will be displayed on the main spots page |
| `limit` | 25, 50, 100, 200, 500 | 100 | `?limit=100` | Sets the number of alerts that will be displayed on the alerts page | | `limit` | 25, 50, 100, 200, 500 | 100 | `?limit=100` | Sets the number of alerts that will be displayed on the alerts page |
| `max_age` | 300, 600, 1800, 3600 | 1800 | `?max_age=1800` | Sets the maximum age of spots displayed on the map and bands pages, in seconds. | | `max_age` | 300, 600, 1800, 3600 | 1800 | `?max_age=1800` | Sets the maximum age of spots displayed on the map and bands pages, in seconds. |
| `band` | Comma-separated list | (all) | `?band=20m,40m` | Sets the list of bands that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. | | `band` | Comma-separated list | (all) | `?band=20m,40m` | Sets the list of bands that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. |
| `sig` | Comma-separated list | (all) | `?sig=POTA,SOTA,NO_SIG` | Sets the list of SIGs that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. | | `sig` | Comma-separated list | (all) | `?sig=POTA,SOTA,NO_SIG` | Sets the list of SIGs that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. |
| `source` | Comma-separated list | (all) | `?source=Cluster` | Sets the list of sources that will be shown on any spot or alert pages. Available options match the labels of the buttons in the standard web interface. | | `source` | Comma-separated list | (all) | `?source=Cluster` | Sets the list of sources that will be shown on any spot or alert pages. Available options match the labels of the buttons in the standard web interface. |
| `mode_type` | Comma-separated list | (all) | `?mode_type=PHONE,CW` | Sets the list of mode types that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. | | `mode_type` | Comma-separated list | (all) | `?mode_type=PHONE,CW` | Sets the list of mode types that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. |
| `dx_continent` | Comma-separated list | (all) | `?dx_continent=NA,SA` | Sets the list of DX Continents that will be shown on any spot or alert pages. Available options match the labels of the buttons in the standard web interface. | | `dx_continent` | Comma-separated list | (all) | `?dx_continent=NA,SA` | Sets the list of DX Continents that will be shown on any spot or alert pages. Available options match the labels of the buttons in the standard web interface. |
| `de_continent` | Comma-separated list | (all) | `?de_continent=EU` | Sets the list of DE Continents that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. | | `de_continent` | Comma-separated list | (all) | `?de_continent=EU` | Sets the list of DE Continents that will be shown on the spots, bands and map pages. Available options match the labels of the buttons in the standard web interface. |
More will be added soon to allow customisation of filters and other display properties. More will be added soon to allow customisation of filters and other display properties.

View File

@@ -188,4 +188,6 @@ web-ui-options:
max-spot-age: [5, 10, 30, 60] max-spot-age: [5, 10, 30, 60]
max-spot-age-default: 30 max-spot-age-default: 30
alert-count: [25, 50, 100, 200, 500] alert-count: [25, 50, 100, 200, 500]
alert-count-default: 100 alert-count-default: 100
default-color-scheme: "auto"
default-band-color-scheme: "PSK Reporter (Adjusted)"

View File

@@ -24,3 +24,7 @@ WEB_UI_OPTIONS = config["web-ui-options"]
# but for consistency we provide this to the front-end in web-ui-options because it has no impact outside of the web UI. # but for consistency we provide this to the front-end in web-ui-options because it has no impact outside of the web UI.
WEB_UI_OPTIONS["spot-providers-enabled-by-default"] = [p["name"] for p in config["spot-providers"] if p["enabled"] and ( WEB_UI_OPTIONS["spot-providers-enabled-by-default"] = [p["name"] for p in config["spot-providers"] if p["enabled"] and (
"enabled-by-default-in-web-ui" not in p or p["enabled-by-default-in-web-ui"] == True)] "enabled-by-default-in-web-ui" not in p or p["enabled-by-default-in-web-ui"] == True)]
# If spotting to this server is enabled, "API" is another valid spot source even though it does not come from
# one of our proviers. We set that to also be enabled by default.
if ALLOW_SPOTTING:
WEB_UI_OPTIONS["spot-providers-enabled-by-default"].append("API")

View File

@@ -34,13 +34,11 @@ class APIOptionsHandler(tornado.web.RequestHandler):
map(lambda p: p["name"], filter(lambda p: p["enabled"], self.status_data["alert_providers"]))), map(lambda p: p["name"], filter(lambda p: p["enabled"], self.status_data["alert_providers"]))),
"continents": CONTINENTS, "continents": CONTINENTS,
"max_spot_age": MAX_SPOT_AGE, "max_spot_age": MAX_SPOT_AGE,
"spot_allowed": ALLOW_SPOTTING, "spot_allowed": ALLOW_SPOTTING}
"web-ui-options": WEB_UI_OPTIONS}
# If spotting to this server is enabled, "API" is another valid spot source even though it does not come from # If spotting to this server is enabled, "API" is another valid spot source even though it does not come from
# one of our proviers. # one of our proviers.
if ALLOW_SPOTTING: if ALLOW_SPOTTING:
options["spot_sources"].append("API") options["spot_sources"].append("API")
options["web-ui-options"]["spot-providers-enabled-by-default"].append("API")
self.write(json.dumps(options, default=serialize_everything)) self.write(json.dumps(options, default=serialize_everything))
self.set_status(200) self.set_status(200)

View File

@@ -2,8 +2,9 @@ from datetime import datetime
import pytz import pytz
import tornado import tornado
import json
from core.config import ALLOW_SPOTTING from core.config import ALLOW_SPOTTING, WEB_UI_OPTIONS
from core.constants import SOFTWARE_VERSION from core.constants import SOFTWARE_VERSION
from core.prometheus_metrics_handler import page_requests_counter from core.prometheus_metrics_handler import page_requests_counter
@@ -22,5 +23,6 @@ class PageTemplateHandler(tornado.web.RequestHandler):
page_requests_counter.inc() page_requests_counter.inc()
# Load named template, and provide variables used in templates # Load named template, and provide variables used in templates
self.render(self.template_name + ".html", software_version=SOFTWARE_VERSION, allow_spotting=ALLOW_SPOTTING) self.render(self.template_name + ".html", software_version=SOFTWARE_VERSION, allow_spotting=ALLOW_SPOTTING,
web_ui_options=json.dumps(WEB_UI_OPTIONS))

View File

@@ -63,7 +63,7 @@
<p>This software is dedicated to the memory of Tom G1PJB, SK, a friend and colleague who sadly passed away around the time I started writing it in Autumn 2025. I was looking forward to showing it to you when it was done.</p> <p>This software is dedicated to the memory of Tom G1PJB, SK, a friend and colleague who sadly passed away around the time I started writing it in Autumn 2025. I was looking forward to showing it to you when it was done.</p>
</div> </div>
<script src="/js/common.js?v=6"></script> <script src="/js/common.js?v=7"></script>
<script>$(document).ready(function() { $("#nav-link-about").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-about").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -69,8 +69,8 @@
</div> </div>
<script src="/js/common.js?v=6"></script> <script src="/js/common.js?v=7"></script>
<script src="/js/add-spot.js?v=6"></script> <script src="/js/add-spot.js?v=7"></script>
<script>$(document).ready(function() { $("#nav-link-add-spot").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-add-spot").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -112,12 +112,14 @@
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Theme</h5> <h5 class="card-title">Theme</h5>
<div class="form-group"> <p class="card-text spothole-card-text">
<div class="form-check form-check-inline"> <label class="form-check-label" for="color-scheme">UI color scheme</label>
<input class="form-check-input storeable-checkbox" type="checkbox" id="darkMode" value="darkMode" oninput="toggleDarkMode();"> <select id="color-scheme" class="storeable-select form-select d-inline-block" oninput="setColorSchemeFromUI();" style="display: inline-block;">
<label class="form-check-label" for="darkMode">Dark mode</label> <option value="auto">Automatic</option>
</div> <option value="light">Light</option>
</div> <option value="dark">Dark</option>
</select>
</p>
</div> </div>
</div> </div>
</div> </div>
@@ -168,8 +170,8 @@
</div> </div>
<script src="/js/common.js?v=6"></script> <script src="/js/common.js?v=7"></script>
<script src="/js/alerts.js?v=6"></script> <script src="/js/alerts.js?v=7"></script>
<script>$(document).ready(function() { $("#nav-link-alerts").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-alerts").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -112,17 +112,19 @@
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Theme</h5> <h5 class="card-title">Theme</h5>
<div class="form-group"> <p class="card-text spothole-card-text">
<div class="form-check form-check-inline"> <label class="form-check-label" for="color-scheme">UI color scheme</label>
<input class="form-check-input storeable-checkbox" type="checkbox" id="darkMode" value="darkMode" oninput="toggleDarkMode();"> <select id="color-scheme" class="storeable-select form-select d-inline-block" oninput="setColorSchemeFromUI();" style="display: inline-block;">
<label class="form-check-label" for="darkMode">Dark mode</label> <option value="auto">Automatic</option>
</div> <option value="light">Light</option>
<p class="card-text spothole-card-text"> <option value="dark">Dark</option>
Band color scheme<br/> </select>
<select id="band-color-scheme" class="storeable-select form-select d-inline-block" oninput="setBandColorSchemeFromUI();" style="display: inline-block;"> </p>
</select> <p class="card-text spothole-card-text">
</p> <label class="form-check-label" for="band-color-scheme">Band color scheme</label><br/>
</div> <select id="band-color-scheme" class="storeable-select form-select d-inline-block" oninput="setBandColorSchemeFromUI();" style="display: inline-block;">
</select>
</p>
</div> </div>
</div> </div>
</div> </div>
@@ -134,9 +136,9 @@
</div> </div>
<script src="/js/common.js?v=6"></script> <script src="/js/common.js?v=7"></script>
<script src="/js/spotsbandsandmap.js?v=6"></script> <script src="/js/spotsbandsandmap.js?v=7"></script>
<script src="/js/bands.js?v=6"></script> <script src="/js/bands.js?v=7"></script>
<script>$(document).ready(function() { $("#nav-link-bands").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-bands").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -46,10 +46,14 @@
crossorigin="anonymous"></script> crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/tinycolor2@1.6.0/cjs/tinycolor.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/tinycolor2@1.6.0/cjs/tinycolor.min.js"></script>
<script src="https://misc.ianrenton.com/jsutils/utils.js?v=6"></script> <script src="https://misc.ianrenton.com/jsutils/utils.js?v=7"></script>
<script src="https://misc.ianrenton.com/jsutils/storage.js?v=6"></script> <script src="https://misc.ianrenton.com/jsutils/storage.js?v=7"></script>
<script src="https://misc.ianrenton.com/jsutils/ui-ham.js?v=6"></script> <script src="https://misc.ianrenton.com/jsutils/ui-ham.js?v=7"></script>
<script src="https://misc.ianrenton.com/jsutils/geo.js?v=6"></script> <script src="https://misc.ianrenton.com/jsutils/geo.js?v=7"></script>
<script>
// Get Web UI Options from the backend to the frontend as a JS object.
let web_ui_options = JSON.parse('{{ web_ui_options }}'.replace(/&quot;/g, '\"'));
</script>
</head> </head>
<body> <body>

View File

@@ -124,17 +124,19 @@
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Theme</h5> <h5 class="card-title">Theme</h5>
<div class="form-group"> <p class="card-text spothole-card-text">
<div class="form-check form-check-inline"> <label class="form-check-label" for="color-scheme">UI color scheme</label>
<input class="form-check-input storeable-checkbox" type="checkbox" id="darkMode" value="darkMode" oninput="toggleDarkMode();"> <select id="color-scheme" class="storeable-select form-select d-inline-block" oninput="setColorSchemeFromUI();" style="display: inline-block;">
<label class="form-check-label" for="darkMode">Dark mode</label> <option value="auto">Automatic</option>
</div> <option value="light">Light</option>
<p class="card-text spothole-card-text"> <option value="dark">Dark</option>
Band color scheme<br/> </select>
<select id="band-color-scheme" class="storeable-select form-select d-inline-block" oninput="setBandColorSchemeFromUI();" style="display: inline-block;"> </p>
</select> <p class="card-text spothole-card-text">
</p> <label class="form-check-label" for="band-color-scheme">Band color scheme</label><br/>
</div> <select id="band-color-scheme" class="storeable-select form-select d-inline-block" oninput="setBandColorSchemeFromUI();" style="display: inline-block;">
</select>
</p>
</div> </div>
</div> </div>
</div> </div>
@@ -152,9 +154,9 @@
<script src="https://cdn.jsdelivr.net/npm/leaflet.geodesic"></script> <script src="https://cdn.jsdelivr.net/npm/leaflet.geodesic"></script>
<script src="https://cdn.jsdelivr.net/npm/@joergdietrich/leaflet.terminator@1.1.0/L.Terminator.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@joergdietrich/leaflet.terminator@1.1.0/L.Terminator.min.js"></script>
<script src="/js/common.js?v=6"></script> <script src="/js/common.js?v=7"></script>
<script src="/js/spotsbandsandmap.js?v=6"></script> <script src="/js/spotsbandsandmap.js?v=7"></script>
<script src="/js/map.js?v=6"></script> <script src="/js/map.js?v=7"></script>
<script>$(document).ready(function() { $("#nav-link-map").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-map").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -155,14 +155,16 @@
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Theme</h5> <h5 class="card-title">Theme</h5>
<div class="form-group">
<div class="form-check form-check-inline">
<input class="form-check-input storeable-checkbox" type="checkbox" id="darkMode" value="darkMode" oninput="toggleDarkMode();">
<label class="form-check-label" for="darkMode">Dark mode</label>
</div>
</div>
<p class="card-text spothole-card-text"> <p class="card-text spothole-card-text">
Band color scheme<br/> <label class="form-check-label" for="color-scheme">UI color scheme</label>
<select id="color-scheme" class="storeable-select form-select d-inline-block" oninput="setColorSchemeFromUI();" style="display: inline-block;">
<option value="auto">Automatic</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
</p>
<p class="card-text spothole-card-text">
<label class="form-check-label" for="band-color-scheme">Band color scheme</label><br/>
<select id="band-color-scheme" class="storeable-select form-select d-inline-block" oninput="setBandColorSchemeFromUI();" style="display: inline-block;"> <select id="band-color-scheme" class="storeable-select form-select d-inline-block" oninput="setBandColorSchemeFromUI();" style="display: inline-block;">
</select> </select>
</p> </p>
@@ -224,9 +226,9 @@
</div> </div>
<script src="/js/common.js?v=6"></script> <script src="/js/common.js?v=7"></script>
<script src="/js/spotsbandsandmap.js?v=6"></script> <script src="/js/spotsbandsandmap.js?v=7"></script>
<script src="/js/spots.js?v=6"></script> <script src="/js/spots.js?v=7"></script>
<script>$(document).ready(function() { $("#nav-link-spots").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-spots").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -3,8 +3,8 @@
<div id="status-container" class="row row-cols-1 row-cols-md-4 g-4 mt-4"></div> <div id="status-container" class="row row-cols-1 row-cols-md-4 g-4 mt-4"></div>
<script src="/js/common.js?v=6"></script> <script src="/js/common.js?v=7"></script>
<script src="/js/status.js?v=6"></script> <script src="/js/status.js?v=7"></script>
<script>$(document).ready(function() { $("#nav-link-status").addClass("active"); }); <!-- highlight active page in nav --></script> <script>$(document).ready(function() { $("#nav-link-status").addClass("active"); }); <!-- highlight active page in nav --></script>
{% end %} {% end %}

View File

@@ -286,11 +286,11 @@ function loadOptions() {
generateMultiToggleFilterCard("#source-options", "source", options["alert_sources"]); generateMultiToggleFilterCard("#source-options", "source", options["alert_sources"]);
// Populate the Display panel // Populate the Display panel
options["web-ui-options"]["alert-count"].forEach(sc => $("#alerts-to-fetch").append($('<option>', { web_ui_options["alert-count"].forEach(sc => $("#alerts-to-fetch").append($('<option>', {
value: sc, value: sc,
text: sc text: sc
}))); })));
$("#alerts-to-fetch").val(options["web-ui-options"]["alert-count-default"]); $("#alerts-to-fetch").val(web_ui_options["alert-count-default"]);
// Load URL params. These may select things from the various filter & display options, so the function needs // Load URL params. These may select things from the various filter & display options, so the function needs
// to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress // to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress
@@ -312,12 +312,6 @@ function filtersUpdated() {
saveSettings(); saveSettings();
} }
// Function to set dark mode based on the state of the UI toggle in spots, bands and map pages
function toggleDarkMode() {
enableDarkMode($("#darkMode")[0].checked);
saveSettings();
}
// React to toggling/closing panels // React to toggling/closing panels
function toggleFiltersPanel() { function toggleFiltersPanel() {
// If we are going to display the filters panel, hide the display panel // If we are going to display the filters panel, hide the display panel

View File

@@ -229,15 +229,16 @@ function loadOptions() {
options = jsonData; options = jsonData;
// Populate the Display panel // Populate the Display panel
options["web-ui-options"]["max-spot-age"].forEach(sc => $("#max-spot-age").append($('<option>', { web_ui_options["max-spot-age"].forEach(sc => $("#max-spot-age").append($('<option>', {
value: sc * 60, value: sc * 60,
text: sc text: sc
}))); })));
$("#max-spot-age").val(options["web-ui-options"]["max-spot-age-default"] * 60); $("#max-spot-age").val(web_ui_options["max-spot-age-default"] * 60);
getAvailableBandColorSchemes().forEach(sc => $("#band-color-scheme").append($('<option>', { getAvailableBandColorSchemes().forEach(sc => $("#band-color-scheme").append($('<option>', {
value: sc, value: sc,
text: sc text: sc
}))); })));
$("#band-color-scheme").val(web_ui_options["default-band-color-scheme"]);
// First pass loading settings, so we can load the band colour scheme before the filters that need to use it // First pass loading settings, so we can load the band colour scheme before the filters that need to use it
loadSettings(); loadSettings();
@@ -252,7 +253,7 @@ function loadOptions() {
generateMultiToggleFilterCard("#dx-continent-options", "dx_continent", options["continents"]); generateMultiToggleFilterCard("#dx-continent-options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#de-continent-options", "de_continent", options["continents"]); generateMultiToggleFilterCard("#de-continent-options", "de_continent", options["continents"]);
generateModesMultiToggleFilterCard(options["modes"]); generateModesMultiToggleFilterCard(options["modes"]);
generateSourcesMultiToggleFilterCard(options["spot_sources"], options["web-ui-options"]["spot-providers-enabled-by-default"]); generateSourcesMultiToggleFilterCard(options["spot_sources"], web_ui_options["spot-providers-enabled-by-default"]);
// Load URL params. These may select things from the various filter & display options, so the function needs // Load URL params. These may select things from the various filter & display options, so the function needs
// to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress // to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress

View File

@@ -20,8 +20,8 @@ function loadURLParams() {
} }
// Handle other params // Handle other params
updateCheckboxFromParam(params, "dark-mode", "darkMode"); updateSelectFromParam(params, "color-scheme", "color-scheme");
updateSelectFromParam(params, "time-zone", "timeZone"); // Only on Spots and Alerts pages updateSelectFromParam(params, "time-zone", "time-zone"); // Only on Spots and Alerts pages
updateSelectFromParam(params, "limit", "spots-to-fetch"); // Only on Spots page updateSelectFromParam(params, "limit", "spots-to-fetch"); // Only on Spots page
updateSelectFromParam(params, "limit", "alerts-to-fetch"); // Only on Alerts page updateSelectFromParam(params, "limit", "alerts-to-fetch"); // Only on Alerts page
updateSelectFromParam(params, "max_age", "max-spot-age"); // Only on Map & Bands pages updateSelectFromParam(params, "max_age", "max-spot-age"); // Only on Map & Bands pages
@@ -38,10 +38,6 @@ function updateCheckboxFromParam(params, paramName, checkboxID) {
let v = params.get(paramName); let v = params.get(paramName);
if (v != null) { if (v != null) {
$("#" + checkboxID).prop("checked", (v === "true") ? true : false); $("#" + checkboxID).prop("checked", (v === "true") ? true : false);
// Extra check if this is the "dark mode" toggle
if (checkboxID == "darkMode") {
enableDarkMode((v === "true") ? true : false);
}
} }
} }
@@ -50,6 +46,10 @@ function updateSelectFromParam(params, paramName, selectID) {
let v = params.get(paramName); let v = params.get(paramName);
if (v != null) { if (v != null) {
$("#" + selectID).prop("value", v); $("#" + selectID).prop("value", v);
// Extra check if this is the "color scheme" select
if (selectID == "color-scheme") {
setColorScheme(v);
}
} }
} }
@@ -142,30 +142,50 @@ function columnsUpdated() {
saveSettings(); saveSettings();
} }
// Function to set dark mode on or off // Function to set the colour scheme based on the state of the UI select box
function enableDarkMode(dark) { function setColorSchemeFromUI() {
$("html").attr("data-bs-theme", dark ? "dark" : "light"); setColorScheme($("#color-scheme option:selected").val());
const metaThemeColor = document.querySelector("meta[name=theme-color]"); saveSettings();
metaThemeColor.setAttribute("content", dark ? "black" : "white");
const metaAppleStatusBarStyle = document.querySelector("meta[name=apple-mobile-web-app-status-bar-style]");
metaAppleStatusBarStyle.setAttribute("content", dark ? "black-translucent" : "white-translucent");
} }
// Startup function to determine whether to use light or dark mode // Function to set the color scheme. Supported values: "dark", "light", "auto"
function usePreferredTheme() { function setColorScheme(mode) {
// First, work out if we have ever explicitly saved the value of our toggle let effectiveModeDark = mode == "dark";
let val = localStorage.getItem("#darkMode:checked"); if (mode == "auto") {
if (val != null) { effectiveModeDark = window.matchMedia('(prefers-color-scheme: dark)').matches
enableDarkMode(JSON.parse(val));
} else {
// Never set it before, so use the system default theme and set the toggle up to match
let dark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
enableDarkMode(dark);
$("#darkMode").prop('checked', dark);
} }
$("html").attr("data-bs-theme", effectiveModeDark ? "dark" : "light");
const metaThemeColor = document.querySelector("meta[name=theme-color]");
metaThemeColor.setAttribute("content", effectiveModeDark ? "black" : "white");
const metaAppleStatusBarStyle = document.querySelector("meta[name=apple-mobile-web-app-status-bar-style]");
metaAppleStatusBarStyle.setAttribute("content", effectiveModeDark ? "black-translucent" : "white-translucent");
}
// Startup function to determine whether to use light or dark mode, or leave as auto
function usePreferredTheme() {
// Set the value of the select box to the server's default
$("#color-scheme").val(web_ui_options["default-color-scheme"]);
// Work out if we have ever explicitly saved the value of our select box. If so, we set our colour scheme now based
// on that. If not, we let the select retain its default value from Spothole config and apply that.
let val = localStorage.getItem("#color-scheme:value");
if (val != null) {
setColorScheme(JSON.parse(val));
} else {
setColorSchemeFromUI();
}
}
// Sets up a listener on the OS light-dark theme change. If the Spothole user theme is set to Auto, the UI will be
// updated, otherwise if the Spothole user theme is forced to light or dark, that preference will remain.
function listenForOSThemeChange() {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
setColorScheme($("#color-scheme option:selected").val());
});
} }
// Startup // Startup
$(document).ready(function() { $(document).ready(function() {
usePreferredTheme(); usePreferredTheme();
listenForOSThemeChange();
}); });

View File

@@ -161,15 +161,16 @@ function loadOptions() {
options = jsonData; options = jsonData;
// Populate the Display panel // Populate the Display panel
options["web-ui-options"]["max-spot-age"].forEach(sc => $("#max-spot-age").append($('<option>', { web_ui_options["max-spot-age"].forEach(sc => $("#max-spot-age").append($('<option>', {
value: sc * 60, value: sc * 60,
text: sc text: sc
}))); })));
$("#max-spot-age").val(options["web-ui-options"]["max-spot-age-default"] * 60); $("#max-spot-age").val(web_ui_options["max-spot-age-default"] * 60);
getAvailableBandColorSchemes().forEach(sc => $("#band-color-scheme").append($('<option>', { getAvailableBandColorSchemes().forEach(sc => $("#band-color-scheme").append($('<option>', {
value: sc, value: sc,
text: sc text: sc
}))); })));
$("#band-color-scheme").val(web_ui_options["default-band-color-scheme"]);
// First pass loading settings, so we can load the band colour scheme before the filters that need to use it // First pass loading settings, so we can load the band colour scheme before the filters that need to use it
loadSettings(); loadSettings();
@@ -184,7 +185,7 @@ function loadOptions() {
generateMultiToggleFilterCard("#dx-continent-options", "dx_continent", options["continents"]); generateMultiToggleFilterCard("#dx-continent-options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#de-continent-options", "de_continent", options["continents"]); generateMultiToggleFilterCard("#de-continent-options", "de_continent", options["continents"]);
generateModesMultiToggleFilterCard(options["modes"]); generateModesMultiToggleFilterCard(options["modes"]);
generateSourcesMultiToggleFilterCard(options["spot_sources"], options["web-ui-options"]["spot-providers-enabled-by-default"]); generateSourcesMultiToggleFilterCard(options["spot_sources"], web_ui_options["spot-providers-enabled-by-default"]);
// Load URL params. These may select things from the various filter & display options, so the function needs // Load URL params. These may select things from the various filter & display options, so the function needs
// to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress // to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress

View File

@@ -387,15 +387,17 @@ function loadOptions() {
options = jsonData; options = jsonData;
// Populate the Display panel // Populate the Display panel
options["web-ui-options"]["spot-count"].forEach(sc => $("#spots-to-fetch").append($('<option>', { web_ui_options["spot-count"].forEach(sc => $("#spots-to-fetch").append($('<option>', {
value: sc, value: sc,
text: sc text: sc,
selected: sc == web_ui_options["spot-count-default"] // todo remove this?
}))); })));
$("#spots-to-fetch").val(options["web-ui-options"]["spot-count-default"]); $("#spots-to-fetch").val(web_ui_options["spot-count-default"]); // todo setting val doesn't update UI?
getAvailableBandColorSchemes().forEach(sc => $("#band-color-scheme").append($('<option>', { getAvailableBandColorSchemes().forEach(sc => $("#band-color-scheme").append($('<option>', {
value: sc, value: sc,
text: sc text: sc
}))); })));
$("#band-color-scheme").val(web_ui_options["default-band-color-scheme"]);
// First pass loading settings, so we can load the band colour scheme before the filters that need to use it // First pass loading settings, so we can load the band colour scheme before the filters that need to use it
loadSettings(); loadSettings();
@@ -410,7 +412,7 @@ function loadOptions() {
generateMultiToggleFilterCard("#dx-continent-options", "dx_continent", options["continents"]); generateMultiToggleFilterCard("#dx-continent-options", "dx_continent", options["continents"]);
generateMultiToggleFilterCard("#de-continent-options", "de_continent", options["continents"]); generateMultiToggleFilterCard("#de-continent-options", "de_continent", options["continents"]);
generateModesMultiToggleFilterCard(options["modes"]); generateModesMultiToggleFilterCard(options["modes"]);
generateSourcesMultiToggleFilterCard(options["spot_sources"], options["web-ui-options"]["spot-providers-enabled-by-default"]); generateSourcesMultiToggleFilterCard(options["spot_sources"], web_ui_options["spot-providers-enabled-by-default"]);
// Load URL params. These may select things from the various filter & display options, so the function needs // Load URL params. These may select things from the various filter & display options, so the function needs
// to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress // to be called after these are set up, but if the URL params ask for "embedded mode", this will suppress

View File

@@ -110,12 +110,6 @@ function filtersUpdated() {
saveSettings(); saveSettings();
} }
// Function to set dark mode based on the state of the UI toggle in spots, bands and map pages
function toggleDarkMode() {
enableDarkMode($("#darkMode")[0].checked);
saveSettings();
}
// Function to update the band colour scheme in spots, bands and map pages // Function to update the band colour scheme in spots, bands and map pages
function setBandColorSchemeFromUI() { function setBandColorSchemeFromUI() {
setBandColorScheme($("#band-color-scheme option:selected").val()); setBandColorScheme($("#band-color-scheme option:selected").val());