From d1106bce11a5867d8ebf82ca62bb1311a099d138 Mon Sep 17 00:00:00 2001
From: Mario Mariete <11509521+melkati@users.noreply.github.com>
Date: Sat, 1 Jun 2024 00:11:12 +0200
Subject: [PATCH] Fix: Server status dot red. Now shows correctly if connection
is lost Fix: Close button in floating debug window (development aid) on web
server was not working. Update: Renamed url parameter testCaptivePortal to
forcedCaptivePortal (development aid) Fix: Many fixes to web server and
Captive Server Update: Many general improvements to web server and Captive
Server HTML, CSS, and JavaScript files Update: Only shows
captivePortalSettings (development aid) when debug is set
---
data/captiveportal.js | 306 ++++++++++++++++++++++++---------------
data/captiveportal.js.gz | Bin 3052 -> 3249 bytes
data/index.html.gz | Bin 984 -> 984 bytes
data/main.js.gz | Bin 569 -> 569 bytes
data/ota.html.gz | Bin 797 -> 797 bytes
data/preferences.html | 24 +--
data/preferences.html.gz | Bin 4789 -> 4805 bytes
data/preferences.js.gz | Bin 3237 -> 3237 bytes
data/status.html.gz | Bin 2948 -> 2948 bytes
data/style.css | 97 +++++--------
data/style.css.gz | Bin 2480 -> 2412 bytes
11 files changed, 242 insertions(+), 185 deletions(-)
diff --git a/data/captiveportal.js b/data/captiveportal.js
index 14033eab..e118b10b 100644
--- a/data/captiveportal.js
+++ b/data/captiveportal.js
@@ -1,14 +1,16 @@
var captivePortalActive = false;
-var testCaptivePortal = false;
+var forcedCaptivePortal = false;
var captivePortalStatusBarActive = false;
var captivePortalDebug = false;
+var forcedCaptivePortalDebug = false;
var relaxedSecurity = false;
var debugWindowActive = false;
+var canPingServer = false;
// Global variables to store the previous state
var previousData = {
captivePortalActive: false,
- testCaptivePortal: false,
+ forcedCaptivePortal: false,
captivePortalNoTimeout: false
};
@@ -56,11 +58,11 @@ function updateStatusBar(content) {
* @param {boolean} isInitialSetup - Whether this is the initial setup.
*/
function setCaptivePortalSettings(timeToWait, isInitialSetup = false) {
- const disableTimeoutCheckbox = document.getElementById('disableTimeoutCheckbox');
+ const disableTimeoutCheckbox = document.getElementById('cpNoTimeout');
let captivePortalNoTimeout = disableTimeoutCheckbox ? disableTimeoutCheckbox.checked : false;
if (!disableTimeoutCheckbox && !isInitialSetup) {
- console.error('Element with ID "disableTimeoutCheckbox" not found.');
+ console.error('Element with ID "cpNoTimeout" not found.');
return;
}
@@ -81,7 +83,7 @@ function setCaptivePortalSettings(timeToWait, isInitialSetup = false) {
timeToWaitForCaptivePortal: timeToWait,
captivePortalActive,
captivePortalNoTimeout,
- testCaptivePortal,
+ forcedCaptivePortal,
captivePortalDebug,
relaxedSecurity: relaxedSecurity ? true : undefined
})
@@ -92,7 +94,7 @@ function setCaptivePortalSettings(timeToWait, isInitialSetup = false) {
}
if (captivePortalDebug) {
console.log('Captive Portal settings updated on server successfully:', {
- testCaptivePortal,
+ forcedCaptivePortal,
captivePortalActive,
captivePortalNoTimeout,
timeToWaitForCaptivePortal: timeToWait,
@@ -112,7 +114,7 @@ function updateDebugWindow(data) {
if (debugWindowActive) {
const debugContent = document.getElementById('debug-content');
if (debugContent) {
- if (captivePortalDebug) console.log('Updating debug window with data:', data);
+ // if (captivePortalDebug) console.log('Updating debug window with data:', data);
let content = `
captivePortalActive: ${data.captivePortalActive}
captivePortalNoTimeout: ${data.captivePortalNoTimeout}
@@ -120,19 +122,24 @@ function updateDebugWindow(data) {
captivePortalTimeLeft: ${data.captivePortalTimeLeft}
captivePortalDebug: ${data.captivePortalDebug}
`;
- if (data.testCaptivePortal !== undefined) {
- if (captivePortalDebug) console.log('Adding testCaptivePortal to debug window:', data.testCaptivePortal);
- content += `testCaptivePortal: ${data.testCaptivePortal}
`;
+
+ if (relaxedSecurity) {
+ // if (captivePortalDebug) console.log('Adding relaxedSecurity to debug window:', relaxedSecurity);
+ content += `relaxedSecurity: ${relaxedSecurity}
`;
+ }
+ if (forcedCaptivePortal) {
+ // if (captivePortalDebug) console.log('Adding forcedCaptivePortal to debug window:', forcedCaptivePortal);
+ content += `forcedCaptivePortal: ${forcedCaptivePortal}
`;
}
- if (data.relaxedSecurity !== undefined) {
- if (captivePortalDebug) console.log('Adding relaxedSecurity to debug window:', data.relaxedSecurity);
- content += `relaxedSecurity: ${data.relaxedSecurity}
`;
+ if (forcedCaptivePortalDebug) {
+ // if (captivePortalDebug) console.log('Adding forcedCaptivePortalDebug to debug window:', forcedCaptivePortalDebug);
+ content += `forcedCaptivePortalDebug: ${forcedCaptivePortalDebug}
`;
}
debugContent.innerHTML = content;
- debugWindow.style.display = 'block';
+ showDebugWindow(true);
}
} else {
- debugWindow.style.display = 'none';
+ showDebugWindow(false);
}
}
@@ -141,91 +148,117 @@ function updateDebugWindow(data) {
* @param {Object} data - The data received from the server.
*/
function handleCaptivePortalData(data) {
- const changes = {};
- const propertiesToCheck = ['captivePortalActive', 'forceCaptivePortalActive', 'captivePortalNoTimeout', 'captivePortalDebug', 'relaxedSecurity'];
-
- if (captivePortalDebug) console.log('Received captive portal data from server:', data);
-
- // Check for changes in properties
- propertiesToCheck.forEach(key => {
- if (data[key] !== previousData[key]) {
- changes[key] = { previous: previousData[key], current: data[key] };
- previousData[key] = data[key];
- }
- });
-
- if (Object.keys(changes).length > 0 && captivePortalDebug) {
- console.log('Detected changes in captive portal data:', changes);
- }
+ try {
+ const changes = {};
+ const propertiesToCheck = ['captivePortalActive', 'forceCaptivePortalActive', 'captivePortalNoTimeout', 'captivePortalDebug', 'relaxedSecurity'];
- // Update debug mode if present in data
- if (data.captivePortalDebug !== undefined) {
- captivePortalDebug = data.captivePortalDebug;
- debugWindowActive = captivePortalDebug;
- console.log('Captive portal debug mode set to:', captivePortalDebug);
- }
+ console.log('Received captive portal data from server:', data);
- // Update active states
- forceCaptivePortalActive = data.forceCaptivePortalActive || false;
- captivePortalActive = (data.captivePortalActive || false) || forceCaptivePortalActive;
+ // Check for changes in properties
+ propertiesToCheck.forEach(key => {
+ if (data[key] !== previousData[key]) {
+ changes[key] = { previous: previousData[key], current: data[key] };
+ previousData[key] = data[key];
+ }
+ });
- if (captivePortalActive) {
- showCaptivePortalStatusBar(true);
+ if (Object.keys(changes).length > 0) {
+ console.log('Detected changes in captive portal data:', changes);
+ }
- const newStatusContent = forceCaptivePortalActive ? 'Captive portal active (test mode)' : 'Captive portal active';
- updateStatusBar(newStatusContent);
+ // Update debug mode if present in data
+ if (data.captivePortalDebug !== undefined) {
+ captivePortalDebug = data.captivePortalDebug;
+ // debugWindowActive = captivePortalDebug;
+ console.log('Captive portal debug mode set to:', captivePortalDebug);
+ }
- const statusContentElement = document.getElementById('status-content');
- if (statusContentElement) {
- if (data.captivePortalNoTimeout) {
- statusContentElement.innerHTML = `
- Timeout Disabled
- Enable
- `;
+ // Update active states
+ forcedCaptivePortal = data.forceCaptivePortalActive || false;
+ captivePortalActive = (data.captivePortalActive || false) || forcedCaptivePortal;
+
+ if (captivePortalActive) {
+ showCaptivePortalStatusBar(true);
+
+ const newStatusContent = forcedCaptivePortal ? 'Captive portal active (test mode)' : 'Captive portal active';
+ updateStatusBar(newStatusContent);
+
+ const statusContentElement = document.getElementById('status-content');
+ if (statusContentElement) {
+ if (data.captivePortalNoTimeout) {
+ statusContentElement.innerHTML = `
+ Timeout Disabled
+ Enable
+ `;
+ } else {
+ statusContentElement.innerHTML = `
+ Timeout: ${data.captivePortalTimeLeft} s
+ Disable
+ `;
+ }
} else {
- statusContentElement.innerHTML = `
- Timeout: ${data.captivePortalTimeLeft} s
- Disable
- `;
+ console.error('Element with ID "status-content" not found.');
}
- } else {
- console.error('Element with ID "status-content" not found.');
- }
- const disableTimeoutCheckbox = document.getElementById('disableTimeoutCheckbox');
- if (disableTimeoutCheckbox) {
- disableTimeoutCheckbox.addEventListener('change', function () {
- const timeToWait = this.checked ? 0 : data.timeToWaitForCaptivePortal;
- console.log('Setting time to wait:', timeToWait);
- setCaptivePortalSettings(timeToWait);
- });
+ const disableTimeoutCheckbox = document.getElementById('disableTimeoutCheckbox');
+ if (disableTimeoutCheckbox) {
+ disableTimeoutCheckbox.addEventListener('change', function () {
+ const timeToWait = this.checked ? 0 : data.timeToWaitForCaptivePortal;
+ console.log('Setting time to wait:', timeToWait);
+ setCaptivePortalSettings(timeToWait);
+ });
+ }
+ } else {
+ showCaptivePortalStatusBar(false);
}
- } else {
- showCaptivePortalStatusBar(false);
- }
- updateServerStatusDot(); // Ensure the status dot is updated after handling captive portal data
+ updateServerStatusDot(); // Ensure the status dot is updated after handling captive portal data
- if (debugWindowActive) {
- updateDebugWindow(data);
+ if (debugWindowActive) {
+ updateDebugWindow(data);
+ }
+ } catch (error) {
+ console.error('Error in handleCaptivePortalData function:', error);
+ throw error; // Re-throw the error to be caught in the fetch catch block
}
}
+
/**
* Fetches the captive portal settings from the server.
*/
function getCaptivePortalSettings() {
- fetch('/getCaptivePortalStatusAsJson')
- .then(response => response.json())
+ fetch("/getCaptivePortalStatusAsJson")
+ .then(response => {
+ console.log("Received response:", response);
+
+ // Check if the response status is OK
+ if (!response.ok) {
+ console.error("Response not OK:", response.status, response.statusText);
+ throw new Error("Network response was not ok " + response.statusText);
+ }
+
+ // Convert the response body to JSON
+ return response.json();
+ })
.then(captivePortalSettings => {
- handleCaptivePortalData(captivePortalSettings);
+ console.log("Received JSON:", captivePortalSettings);
+
+ // Handle the JSON data
+ try {
+ handleCaptivePortalData(captivePortalSettings);
+ } catch (e) {
+ console.error("Error in handleCaptivePortalData:", e);
+ throw e; // Re-throw the error to be caught in the catch block
+ }
})
.catch(error => {
- console.error('Error fetching captive portal status:', error);
- showServerStatusDot(true, 'status-dot-red', 'Connection to server lost');
+ console.error("Error fetching captive portal status:", error);
+ // showServerStatusDot(true, "status-dot-red", "Connection to server lost");
});
}
+
let previousServerStatusDotState = {
show: null,
colorClass: '',
@@ -238,7 +271,7 @@ let previousServerStatusDotState = {
* @param {string} [colorClass] - The color class to apply.
* @param {string} [title] - The title to apply for hover text.
*/
-function showServerStatusDot(show, colorClass = 'status-dot-white', title = '') {
+function displayServerStatusDot(show, colorClass = 'status-dot-cyan', title = '') {
const serverStatusDot = document.getElementById('server-status-dot');
if (serverStatusDot) {
const hasStateChanged =
@@ -272,16 +305,15 @@ function checkServerConnection() {
fetch('/pingServer')
.then(response => {
if (response.ok) {
- updateServerStatusDot(); // Update status dot based on current state
+ canPingServer = true;
} else {
+ canPingServer = false;
captivePortalActive = false; // Mark captive portal as inactive
- updateServerStatusDot(); // Update status dot to reflect the lost connection
}
})
.catch(error => {
console.error('Error pinging server:', error);
captivePortalActive = false; // Mark captive portal as inactive
- updateServerStatusDot(); // Update status dot to reflect the lost connection
});
}
@@ -291,26 +323,30 @@ function checkServerConnection() {
function updateServerStatusDot() {
let show, colorClass, title;
- if (!captivePortalActive) {
+ if (!canPingServer) {
+ show = true;
+ colorClass = 'status-dot-red';
+ title = 'Connection to server lost';
+ } else if (!captivePortalActive) {
show = false;
colorClass = 'status-dot-hidden';
title = 'Captive portal inactive';
- } else if (forceCaptivePortalActive) {
+ } else if (forcedCaptivePortal) {
show = true;
colorClass = 'status-dot-blue';
title = 'Captive portal active (test mode)';
} else {
show = true;
- colorClass = 'status-dot-white';
+ colorClass = 'status-dot-cyan';
title = 'Captive portal active';
}
- // Call showServerStatusDot with the new state
- showServerStatusDot(show, colorClass, title);
+ // Call displayServerStatusDot with the new state
+ displayServerStatusDot(show, colorClass, title);
if (captivePortalDebug) {
console.log('Updated server status dot based on captive portal status');
- console.log('captivePortalActive:', captivePortalActive, 'forceCaptivePortalActive:', forceCaptivePortalActive);
+ console.log('captivePortalActive:', captivePortalActive, 'forcedCaptivePortal:', forcedCaptivePortal);
}
}
@@ -333,7 +369,7 @@ function initializeCaptivePortalStatusBar() {
`;
- if (testCaptivePortal) showCaptivePortalStatusBar(true);
+ if (forcedCaptivePortal) showCaptivePortalStatusBar(true);
} else {
console.error('Element with ID "captive-portal-status-bar" not found.');
}
@@ -344,13 +380,14 @@ function initializeCaptivePortalStatusBar() {
*/
function setupInitialSettings() {
if (window.location.href.includes("debugCaptivePortal")) {
+ forcedCaptivePortalDebug = true;
captivePortalDebug = true;
- console.log('Forcing captive portal debug mode to be active by parameter in URL');
+ console.log('Forcing captive portal debug mode to be active by debugCaptivePortal parameter in URL');
}
- if (window.location.href.includes("testCaptivePortal")) {
- if (captivePortalDebug) console.log('Forcing captive portal to be active in test mode by parameter in URL');
- testCaptivePortal = true;
+ if (window.location.href.includes("forcedCaptivePortal")) {
+ if (captivePortalDebug) console.log('Forcing captive portal to be active in test mode by forcedCaptivePortal parameter in URL');
+ forcedCaptivePortal = true;
captivePortalActive = true;
}
@@ -463,7 +500,7 @@ function initializeThemeSwitch() {
function initializeCaptivePortal() {
if (captivePortalDebug) console.log('Document loaded. Initializing captive portal for preferences.html');
- getCaptivePortalSettings(); // Fetch initial settings
+ // getCaptivePortalSettings(); // Fetch initial settings
setupInitialSettings();
initializeCaptivePortalStatusBar();
updateStatusBarContent();
@@ -474,24 +511,6 @@ function initializeCaptivePortal() {
highlightCurrentPage(); // Highlight the current page in the navigation
}
-/**
- * Create the debug window and its content.
- * @param {HTMLElement} debugWindow - The debug window element.
- */
-function createDebugWindow(debugWindow) {
- const closeButton = document.createElement('button');
- closeButton.id = 'close-debug-window';
- closeButton.innerHTML = '[X]';
- closeButton.onclick = () => {
- debugWindow.style.display = 'none';
- };
- debugWindow.appendChild(closeButton);
-
- const debugContent = document.createElement('div');
- debugContent.id = 'debug-content';
- debugWindow.appendChild(debugContent);
-}
-
document.addEventListener("DOMContentLoaded", function () {
const currentPage = window.location.pathname.split("/").pop();
@@ -505,8 +524,8 @@ document.addEventListener("DOMContentLoaded", function () {
if (captivePortalDebug) console.log('Not on preferences.html, skipping debug window initialization');
}
+ const debugWindow = document.getElementById('debug-window');
if (captivePortalDebug) {
- const debugWindow = document.getElementById('debug-window');
if (debugWindow) {
createDebugWindow(debugWindow);
debugWindowActive = true;
@@ -515,7 +534,68 @@ document.addEventListener("DOMContentLoaded", function () {
console.error('Element with ID "debug-window" not found.');
}
} else {
- debugWindow.style.display = 'none';
- debugWindowActive = true;
+ if (debugWindow) {
+ debugWindow.style.display = 'none';
+ debugWindowActive = false;
+ }
}
});
+
+/**
+ * Shows or hides the captivePortalSettings fieldset based on the provided flag.
+ * @param {boolean} show - Determines whether to show or hide the captivePortalSettings fieldset.
+ */
+function showCaptivePortalSettings(show) {
+ const captivePortalSettings = document.getElementById('captivePortalSettings');
+ if (captivePortalSettings) {
+ if (show) {
+ captivePortalSettings.classList.remove('hidden');
+ } else {
+ captivePortalSettings.classList.add('hidden');
+ }
+ } else {
+ console.error('Element with ID "captivePortalSettings" not found.');
+ }
+}
+
+/**
+ * Shows or hides the debug window based on the provided flag.
+ * @param {boolean} show - Flag indicating whether to show or hide the debug window.
+ */
+function showDebugWindow(show) {
+ const debugWindow = document.getElementById('debug-window');
+ if (debugWindow) {
+ if (show) {
+ debugWindow.classList.remove('hidden-debug-window');
+ debugWindow.style.display = 'block';
+ debugWindowActive = true;
+ if (captivePortalDebug) console.log('Showing debug window');
+ } else {
+ debugWindow.classList.add('hidden-debug-window');
+ debugWindow.style.display = 'none';
+ debugWindowActive = false;
+ if (captivePortalDebug) console.log('Hiding debug window');
+ }
+ } else {
+ console.error('Element with ID "debug-window" not found.');
+ }
+ showCaptivePortalSettings(show); // Show captive portal settings when debug window is shown (for development)
+}
+
+/**
+ * Creates a debug window with a close button and debug content.
+ */
+function createDebugWindow() {
+ const debugWindow = document.getElementById('debug-window');
+ const closeButton = document.createElement('button');
+ closeButton.id = 'close-debug-window';
+ closeButton.innerHTML = '[X]';
+ closeButton.onclick = () => {
+ showDebugWindow(false);
+ };
+ debugWindow.appendChild(closeButton);
+
+ const debugContent = document.createElement('div');
+ debugContent.id = 'debug-content';
+ debugWindow.appendChild(debugContent);
+}
diff --git a/data/captiveportal.js.gz b/data/captiveportal.js.gz
index 5eefc57aad2c528c0ac3ebf2e9bab6b2acb46def..8ebc67e7c869bed131964d01e0efd1632778bdd2 100644
GIT binary patch
delta 3247
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
delta 3048
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
diff --git a/data/index.html.gz b/data/index.html.gz
index 45a900f730b0f356b2edc2aac4e30da9415fe626..8432c18d77019d07f9a675fc75c0f098310e54d7 100644
GIT binary patch
delta 16
Xcmcb?euJG|zMF%i*)wV*`$c8|Elve8
delta 16
Xcmcb?euJG|zMF%i>0ZP}_KVB_FuMiB
diff --git a/data/main.js.gz b/data/main.js.gz
index 8f5722c57fa34a2718b302f88ca431746df57a17..820727826c130bb13a769af6bd6e62b7574d32dc 100644
GIT binary patch
delta 16
XcmdnVvXg~fzMF%i*)wV*yAcxrC>aD!
delta 16
XcmdnVvXg~fzMF%i>0ZP}b|WSLD~1H%
diff --git a/data/ota.html.gz b/data/ota.html.gz
index bc472bfa59dc7be5fefde43dbe1083cea7702dbf..b6022e98321babeb590dc44cd68cf009cb3cb7a9 100644
GIT binary patch
delta 16
XcmbQsHkXZEzMF%i#WQLnyBIS7B-sQ2
delta 16
XcmbQsHkXZEzMF%i`Ci0Eb}?oEC`JU5
diff --git a/data/preferences.html b/data/preferences.html
index d6ba4ce6..deefcb7b 100644
--- a/data/preferences.html
+++ b/data/preferences.html
@@ -24,7 +24,7 @@
-
+
Home
@@ -40,18 +40,17 @@
+ d="M12,2A7,7 0 0,0 5,9C5,11.38 6.19,13.47 8,14.74V17A1,1 0 0,0 9,18H15A1,1,0 0,0 16,17V14.74C17.81,13.47 19,11.38 19,9A7,7 0 0,0 12,2M9,21A1,1 0 0,0 10,22H14A1,1 0 0,0 15,21V20H9V21Z" />
+
+
-
-
-
@@ -122,9 +121,9 @@
CO2 Gadget Preferences
-
+
-
+
Captive Portal
No Timeout:
@@ -182,7 +181,7 @@ CO2 Gadget Preferences
ℹ️
Use a fixed IP address for the device. This is useful for devices
that need to be accessed by a fixed IP address.
-
+
-
-
+
+
+
@@ -340,7 +339,8 @@ CO2 Gadget Preferences
Auto Self Calibration:
ℹ️
- Enable automatic self-calibration of the CO2 sensor. Not recommended
+ Enable automatic self-calibration of the CO2 sensor. Not
+ recommended
if the sensor is not exposed to fresh air (~420ppm) at least once a week.
diff --git a/data/preferences.html.gz b/data/preferences.html.gz
index c7b6ac9979b82fabc9961f88c78c054d44cc8054..0bff6b72e542bf31bb209258b3419ba4a45bb6df 100644
GIT binary patch
literal 4805
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
literal 4789
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
PfBW%oDuX{NHBtZo$)+oO
diff --git a/data/preferences.js.gz b/data/preferences.js.gz
index a05641fc0df463492a3baf3b9748b8be395eb75b..39e6ba2048d56f4ba20593ceb046901dc5ffd989 100644
GIT binary patch
delta 16
XcmZ1~xm1!}zMF%i#WQLn`#c^1DE0)$
delta 16
XcmZ1~xm1!}zMF%i`Ci0E_IW%2EMo;(
diff --git a/data/status.html.gz b/data/status.html.gz
index 3ea87da1ee5b38283129211331f28608d1b67a53..d1f6c5224e8b9eb714a96caeb93d9ff3e330a7e1 100644
GIT binary patch
delta 16
XcmZn>ZxLsg@8;lW@r>HYUds&tB%K6b
delta 16
XcmZn>ZxLsg@8;lWz8A5Py_OpQC<+Ae
diff --git a/data/style.css b/data/style.css
index 36c97e02..639e1b50 100644
--- a/data/style.css
+++ b/data/style.css
@@ -15,7 +15,7 @@
--input-background-color: #fff;
--button-background-color: #4caf50;
--button-hover-background-color: #45a049;
- --tag-dark-bg-color: #2c3e50; /* Dark theme tag background color */
+ --tag-dark-bg-color: #2c3e50;
--popup-bg-color: #333;
--popup-text-color: #fff;
--tooltip-bg-color: #555;
@@ -26,7 +26,6 @@
--close-button-hover-color: darkred;
--status-bar-bg-color: #fbef83;
--status-bar-text-color: #333;
- --navbar-height: 60px;
}
[theme='dark'] {
@@ -57,16 +56,13 @@
--close-button-hover-color: #c0392b;
--status-bar-bg-color: #34495e;
--status-bar-text-color: #ecf0f1;
- --navbar-height: 60px;
}
-/* Body Styles */
body {
font-family: 'Arial', sans-serif;
background-color: var(--bg-color);
color: var(--font-color);
margin: 0;
- padding-top: var(--navbar-height);
}
h1, h2, h3, h4 {
@@ -92,21 +88,24 @@ h4 {
font-size: 1.25em;
}
-/* Navigation Bar Styles */
.navbar {
- overflow: hidden;
- position: fixed;
- top: 0;
+ display: flex;
+ flex-direction: column;
width: 100%;
- color: var(--navbar-text-color);
background-color: var(--navbar-background-color);
- padding: 15px 10px;
+ padding: 0;
border-bottom: 1px solid var(--navbar-border-color);
box-shadow: var(--navbar-shadow);
z-index: 1000;
+ position: relative;
+}
+
+.nav-content {
display: flex;
justify-content: space-between;
align-items: center;
+ width: 100%;
+ padding: 15px 10px;
}
.navbar a {
@@ -125,13 +124,6 @@ h4 {
pointer-events: none;
}
-.nav-content {
- display: flex;
- justify-content: space-between;
- align-items: center;
- width: 100%;
-}
-
.nav-links-left,
.nav-links-right {
display: flex;
@@ -143,19 +135,11 @@ h4 {
}
.iconDarkLight {
- position: absolute;
- top: 1.2%;
- right: 2%;
- background-color: transparent;
- transition: transform 0.05s;
- z-index: 1000;
+ margin-left: 10px;
+ margin-right: 1rem;
cursor: pointer;
width: 24px;
height: 24px;
- /* background-image: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20style%3D%22width%3A24px%3Bheight%3A24px%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20fill%3D%22var(--icon-color)%22%20d%3D%22M12%2C2A7%2C7%200%200%2C0%205%2C9C5%2C11.38%206.19%2C13.47%208%2C14.74V17A1%2C1%200%200%2C0%209%2C18H15A1%2C1%200%200%2C0%2016%2C17V14.74C17.81%2C13.47%2019%2C11.38%2019%2C9A7%2C7%200%200%2C0%2012%2C2M9%2C21A1%2C1%200%200%2C0%2010%2C22H14A1%2C1%200%200%2C0%2015%2C21V20H9V21Z%22%20%2F%3E%3C%2Fsvg%3E'); */
- background-repeat: no-repeat;
- background-position: center;
- background-size: contain;
}
.iconDarkLight:hover {
@@ -166,7 +150,6 @@ h4 {
transform: scale(1.5);
}
-/* Styles for the tag class */
.tag {
font-size: 1.2em;
color: var(--bg-color);
@@ -186,7 +169,6 @@ h4 {
background-color: var(--tag-dark-bg-color);
}
-/* Form Styles */
#preferencesForm {
background-color: var(--bg-color);
border-radius: 8px;
@@ -247,7 +229,7 @@ button {
border-radius: 4px;
cursor: pointer;
font-size: 16px;
- margin: 5px; /* Ajuste del margen para un espaciado uniforme */
+ margin: 5px;
transition: background-color 0.3s ease;
}
@@ -264,12 +246,12 @@ button:hover {
.buttonGroup {
display: flex;
justify-content: space-between;
- flex-wrap: nowrap; /* Mantener los botones en una fila en pantallas anchas */
+ flex-wrap: nowrap;
}
.buttonsBackupRestore, .buttonsRestartSave {
display: flex;
- gap: 10px; /* Añadir espacio entre los botones */
+ gap: 10px;
}
#backupButton, #restoreButton {
@@ -282,21 +264,21 @@ button:hover {
@media screen and (max-width: 600px) {
.buttonGroup {
- display: grid; /* Usar grid layout para pantallas estrechas */
- grid-template-columns: 1fr 1fr; /* Dos columnas de igual ancho */
- gap: 20px; /* Espacio entre columnas y filas */
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 20px;
}
.buttonsBackupRestore, .buttonsRestartSave {
flex-direction: column;
width: auto;
margin-bottom: 0;
- align-items: center; /* Centrar los botones en cada columna */
+ align-items: center;
}
.buttonsBackupRestore button, .buttonsRestartSave button {
- width: 100%; /* Asegurar que los botones ocupen todo el ancho de la columna */
- margin-bottom: 10px; /* Mayor separación vertical entre botones */
+ width: 100%;
+ margin-bottom: 10px;
}
.buttonGroup button {
@@ -319,19 +301,16 @@ button:hover {
}
}
-
.content {
max-width: 600px;
margin: 0 auto;
- padding-top: var(--navbar-height); /* Add padding to ensure content is not hidden by navbar */
}
-/* Circular Chart Styles */
.flex-wrapper {
display: flex;
flex-flow: row nowrap;
justify-content: space-around;
- align-items: center; /* Center items vertically */
+ align-items: center;
}
.single-chart {
@@ -339,7 +318,7 @@ button:hover {
position: relative;
display: flex;
flex-direction: column;
- align-items: center; /* Center items horizontally */
+ align-items: center;
}
.circular-chart {
@@ -415,7 +394,6 @@ button:hover {
}
}
-/* Popup Styles */
#popup {
display: none;
position: fixed;
@@ -480,24 +458,19 @@ button:hover {
visibility: visible;
}
-/* Captive Portal Status Bar */
#captive-portal-status-bar {
width: 100%;
background-color: var(--status-bar-bg-color);
color: var(--status-bar-text-color);
- position: fixed;
- top: 45px;
- z-index: 999;
+ position: relative;
+ z-index: 1;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.7em;
-}
-
-@media (max-width: 600px) {
- #captive-portal-status-bar {
- top: 45px;
- }
+ padding: 5px;
+ box-sizing: border-box;
+ overflow: hidden;
}
#hide-captive-portal-status-bar-button {
@@ -506,6 +479,8 @@ button:hover {
padding: 5px 10px;
font-size: 0.7em;
cursor: pointer;
+ display: flex;
+ align-items: center;
}
#hide-captive-portal-status-bar-button svg {
@@ -524,7 +499,6 @@ button:hover {
display: none !important;
}
-/* Status Dot Styles */
.status-dot {
width: 10px;
height: 10px;
@@ -542,6 +516,10 @@ button:hover {
background-color: white;
}
+.status-dot-cyan {
+ background-color: cyan;
+}
+
.status-dot-blue {
background-color: blue;
}
@@ -558,7 +536,6 @@ button:hover {
font-weight: bold;
}
-/* Add a fade animation effect */
@keyframes fadeInOut {
0% {
opacity: 0;
@@ -583,21 +560,21 @@ button:hover {
right: 10px;
width: auto;
height: auto;
- pointer-events: none;
+ pointer-events: auto; /* Ensure interaction is possible */
font-size: 0.9em;
background-color: var(--debug-bg-color);
border: 1px solid var(--debug-border-color);
border-radius: 10px;
padding: 10px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
- display: none;
+ display: none; /* Default state is hidden */
overflow: auto;
z-index: 9998;
animation: fadeInOut 2s ease-in-out;
}
.hidden-debug-window {
- display: none;
+ display: none !important;
}
#close-debug-window {
diff --git a/data/style.css.gz b/data/style.css.gz
index 2d4439d0f04ff03d10ddd14f2a387124418f0eef..c8b3db1f035eaba64a211a0750031fa13da0db55 100644
GIT binary patch
literal 2412
zcmV-y36u68iwFpWNm^zE0CRMCY-KKOX>KlKb8`UIS#7VAFckhPs4==Y7GB2OSWJA2
z#>7OUiC>H#3Y4wNfV9l1g#Yeo3lv(I({JYH-m&&@dd}1HenVOmRc+g8kymzHWCacH
zZ8n>|ZAXXhdzz;3y&_eHyQSR*V~k*x#6{k}hxrdI#)QU-7ARpYN8ckv?Fhx+4zxJu
zNzZ+o?oy;ED*U6D#P@x*aV)-L+U+<_u!#nnQ9%>6iy!kJwabnuDK4R7t;-+Q27c)w
zLJys#_*uCNpgdv(3?vTf^ln2xAW0Igd|sX_Z6}W7en%-ghB7)=Rgq6@uVa)3PER3K
zo}vqov)=JbK?gfQ^xNRJyx7NrM_H8Tl5Z$=x>W_Ty56G5Dl()Gf}mfYdLzNn`Jm_p
zq^=(}z=%xrP>%1|SmZhf^o
zVNT8G>WEMH$pg;n!57W)ahy7-3k-BPb^CWw6z}5J{>N_{_V2IPyWpw|xT%-;iRl80
zspbV^G3LC$jlHe!-|7XMu@`6pbbB*rn7*Jizv2#lv_=7%^9ZHkpFP6eAZHtx9-+kO
zY=7QWOxTtEo9xt<`QD6o_`BuCS-S4yIp0w1H7`(sZ5{jZH5a)TJO0j#bQdwWtKA9t
zo2W>B*1`%>bRyZ$@WC@mQ1)QSP|j?IDM|OnC45Kpp>mzYez?kcb?YZY4T$r={Lz|NT91}IzP6H%Rwsm&8TuKf8UC^7f9!-%99N{sLy+Wr
z%J&zNRL9VDocl94n$bd2B6Kta+z|qkF<}9({OIDqkg8o0{mM9$3~WW*P`t9ygSVqP$f^5LhdpSr{>_jtPYejf~KYw+ltT
zLNUjq?#iLv4!|N@FB^Xc{TP?Cg)1ZZH)dxzt(JrDlpKy4geFLh{sI6ZJwfmbUCOPF
z=b)Dm^4@Za@jh2yE{ON#8~gZ78Hmj#RyX0Tf%b?wm3Y?pwg?F<(}JEt7NZP5bfJ3E
zDO+qz(f~*yK93y-9PLXDfL~)te86>1!8lNzDWtr5{9c7DXNjNOA%!IQ|B5
z_NtVBXk+4Da(Q~
za&h9&Zfg+54A<5SpnGHNY`qiWtbnD~2PW(*p1N
z_stT1e?xOJ#h=eK&KaWZ2_2VVdX%sTqf%gOo%`ZjS6K$)>e~rP1hpW^GFjBKiWc9n
z2twl#%A(zBIr^(@$3VS3Ch=C=ZhIKn+
zHBZ0cpD9Hr%&d;EcJ9|L&jc|5fr9$H6?GaN9k2<{YDH|{;X|`s3bZ;Y_jQAI9mkJ%
zChhTjA_lD=?=TLU)pwMgB_MKwJM7+7*FLc5)nj~W>*YK?LgYS?B*~y@Ip?JMD@Oh#
zqb?E_dG>QI9Qr#R4#&>X`$KDv7T@@@&EJqhTK8#9(f7U|WgwJ~>Rf(c->Jyj5mO6z
zB{*j|v3AaV3-Ni#{z6H`2MVVm0n5d-BGBsCG?Q=?l)&NA-p-}SAx(2n44XP}h4Csc
zP00^PpH)$Y0r(A1D&j%4QsRl{hKDw6Ecu_=8b=&7DD{oK$)5Y;mPw8!maRBChU8
z61XG@f4_*cjFgNp5r|Y$x+zsp$v8|?-XJYVSm27m|6ilzfU8fKGJs$lE^jQD|2$wb
z($PP6b0+8}$jz!7c=C3?9v7x+le4P76GkGEk?Lo6BQ5M(IDJkr$zjf7&1vg|*ct#E
zt%iVKpwgtI5%91PU?AEe1+4T155A(Jg1+&=q
zLwj+a(@)Lh^GrQs4)YgU$#Ub_(&U5$vj=EHO9}cs=TR=Q?vRt9$idcInxv?DJ5}ns
z6Mda?e|j)x++?3C#U=EmhdR)fQV(St?~4Fswx4`?Oc?(}6KyJA9g=~d=LvRvbwmd3
z?PSl}5ea*$&332Xms2KvHZ`m```E)v&H|i~hZ3jp0`<*p9*@4c&WN;G$^R@}z~75Y
zt(6zU`HFI-K~LD;uz1$y+G1_!WIKGC4qW=bz!v7zWPDx%QfH{-Zc3=(
e|2+N}MDEEqyJlA_$(q%axBdn>2bo%2A^-s9XREdV
literal 2480
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