change to color blue

This commit is contained in:
pablorevilla-meshtastic committed 2026-10-30 13:56:25 -07:00
1 parent e1e34c120e
commit e4483ec02a
14 files changed
+208 -198

No files matched your search

+33 -33
View File
@@ -17,47 +17,47 @@ code { background:var(--mesh-soft); padding:3px 6px; border-radius:4px; overflow
<style>
:root {
color-scheme:light;
--mesh-primary:#187346;
--mesh-primary-dark:#0f5132;
--mesh-primary-rgb:24,115,70;
--mesh-brand:#187346;
--mesh-brand-deep:#0f5132;
--mesh-primary:#245ea8;
--mesh-primary-dark:#19467f;
--mesh-primary-rgb:36,94,168;
--mesh-brand:#245ea8;
--mesh-brand-deep:#19467f;
--mesh-surface:#ffffff;
--mesh-text:#243247;
--mesh-soft:#eaf5ee;
--mesh-hover:#dceee2;
--mesh-border:#dce7df;
--mesh-page:#f5f9f6;
--mesh-stripe:#f7faf8;
--mesh-soft:#eaf1fb;
--mesh-hover:#dce8f8;
--mesh-border:#dce4ef;
--mesh-page:#f5f8fc;
--mesh-stripe:#f7f9fc;
--mesh-muted:#64748b;
--mesh-chat-stripe:#eef6f0;
--mesh-pulse-soft:#edf8f0;
--mesh-pulse-peak:#ccebd7;
--mesh-pulse-mid:#e2f3e8;
--mesh-chat-stripe:#eef3fb;
--mesh-pulse-soft:#edf4ff;
--mesh-pulse-peak:#c9defa;
--mesh-pulse-mid:#deebfc;
}
[data-bs-theme="dark"] {
color-scheme:dark;
--mesh-primary:#80cfa3;
--mesh-primary-dark:#a3e3be;
--mesh-primary-rgb:128,207,163;
--mesh-brand:#14532d;
--mesh-brand-deep:#0c3a1f;
--mesh-surface:#18231e;
--mesh-text:#e2ece5;
--mesh-soft:#203c2b;
--mesh-hover:#294c36;
--mesh-border:#34483c;
--mesh-page:#101914;
--mesh-stripe:#1c2a22;
--mesh-muted:#9faea6;
--mesh-chat-stripe:#203227;
--mesh-pulse-soft:#203c2b;
--mesh-pulse-peak:#356b49;
--mesh-pulse-mid:#294c36;
--mesh-primary:#8bbcff;
--mesh-primary-dark:#b6d5ff;
--mesh-primary-rgb:139,188,255;
--mesh-brand:#193d69;
--mesh-brand-deep:#112b4b;
--mesh-surface:#182335;
--mesh-text:#e2eaf6;
--mesh-soft:#203653;
--mesh-hover:#29486c;
--mesh-border:#34465f;
--mesh-page:#101925;
--mesh-stripe:#1c2a3d;
--mesh-muted:#a0aec2;
--mesh-chat-stripe:#20314a;
--mesh-pulse-soft:#203653;
--mesh-pulse-peak:#355d8e;
--mesh-pulse-mid:#29486c;
--bs-link-color:var(--mesh-primary);
--bs-link-color-rgb:var(--mesh-primary-rgb);
--bs-link-hover-color:var(--mesh-primary-dark);
--bs-link-hover-color-rgb:163,227,190;
--bs-link-hover-color-rgb:182,213,255;
}
body { background:var(--mesh-page); color:var(--mesh-text); }
.mesh-theme-toggle { flex-shrink:0; display:inline-flex; align-items:center; justify-content:center; width:34px; height:34px; border:1px solid #ffffff70; border-radius:6px; background:transparent; color:white; font:22px/1 system-ui,sans-serif; cursor:pointer; }
@@ -92,7 +92,7 @@ body { background:var(--mesh-page); color:var(--mesh-text); }
<!-- mesh-theme:end -->
</head>
<body>
<button class="mesh-theme-toggle" style="position:fixed;top:12px;right:12px;z-index:2000;background:#187346" type="button" data-theme-toggle aria-label="Switch to night mode" aria-pressed="false"><svg class="theme-icon theme-icon--sun" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M4.93 4.93l1.42 1.42m11.3 11.3 1.42 1.42M4.93 19.07l1.42-1.42m11.3-11.3 1.42-1.42"/></svg><svg class="theme-icon theme-icon--moon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20.9 13A9 9 0 0 1 11 3.1 9 9 0 1 0 20.9 13Z"/></svg></button><main>
<button class="mesh-theme-toggle" style="position:fixed;top:12px;right:12px;z-index:2000;background:#245ea8" type="button" data-theme-toggle aria-label="Switch to night mode" aria-pressed="false"><svg class="theme-icon theme-icon--sun" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M4.93 4.93l1.42 1.42m11.3 11.3 1.42 1.42M4.93 19.07l1.42-1.42m11.3-11.3 1.42-1.42"/></svg><svg class="theme-icon theme-icon--moon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20.9 13A9 9 0 0 1 11 3.1 9 9 0 1 0 20.9 13Z"/></svg></button><main>
<h1>Chat messages API</h1>
<p>Chat uses <code>GET /api/packets?portnum=1</code>. There is no separate <code>/api/chat</code> endpoint.</p>
<p>Use <code>limit</code> and <code>since</code> for incremental polling. Direct port-1 text messages are returned as <code>&lt;redacted&gt;</code>.</p>
+32 -32
View File
@@ -41,47 +41,47 @@ footer { border-top:1px solid var(--border); padding:20px 24px; text-align:cente
<style>
:root {
color-scheme:light;
--mesh-primary:#187346;
--mesh-primary-dark:#0f5132;
--mesh-primary-rgb:24,115,70;
--mesh-brand:#187346;
--mesh-brand-deep:#0f5132;
--mesh-primary:#245ea8;
--mesh-primary-dark:#19467f;
--mesh-primary-rgb:36,94,168;
--mesh-brand:#245ea8;
--mesh-brand-deep:#19467f;
--mesh-surface:#ffffff;
--mesh-text:#243247;
--mesh-soft:#eaf5ee;
--mesh-hover:#dceee2;
--mesh-border:#dce7df;
--mesh-page:#f5f9f6;
--mesh-stripe:#f7faf8;
--mesh-soft:#eaf1fb;
--mesh-hover:#dce8f8;
--mesh-border:#dce4ef;
--mesh-page:#f5f8fc;
--mesh-stripe:#f7f9fc;
--mesh-muted:#64748b;
--mesh-chat-stripe:#eef6f0;
--mesh-pulse-soft:#edf8f0;
--mesh-pulse-peak:#ccebd7;
--mesh-pulse-mid:#e2f3e8;
--mesh-chat-stripe:#eef3fb;
--mesh-pulse-soft:#edf4ff;
--mesh-pulse-peak:#c9defa;
--mesh-pulse-mid:#deebfc;
}
[data-bs-theme="dark"] {
color-scheme:dark;
--mesh-primary:#80cfa3;
--mesh-primary-dark:#a3e3be;
--mesh-primary-rgb:128,207,163;
--mesh-brand:#14532d;
--mesh-brand-deep:#0c3a1f;
--mesh-surface:#18231e;
--mesh-text:#e2ece5;
--mesh-soft:#203c2b;
--mesh-hover:#294c36;
--mesh-border:#34483c;
--mesh-page:#101914;
--mesh-stripe:#1c2a22;
--mesh-muted:#9faea6;
--mesh-chat-stripe:#203227;
--mesh-pulse-soft:#203c2b;
--mesh-pulse-peak:#356b49;
--mesh-pulse-mid:#294c36;
--mesh-primary:#8bbcff;
--mesh-primary-dark:#b6d5ff;
--mesh-primary-rgb:139,188,255;
--mesh-brand:#193d69;
--mesh-brand-deep:#112b4b;
--mesh-surface:#182335;
--mesh-text:#e2eaf6;
--mesh-soft:#203653;
--mesh-hover:#29486c;
--mesh-border:#34465f;
--mesh-page:#101925;
--mesh-stripe:#1c2a3d;
--mesh-muted:#a0aec2;
--mesh-chat-stripe:#20314a;
--mesh-pulse-soft:#203653;
--mesh-pulse-peak:#355d8e;
--mesh-pulse-mid:#29486c;
--bs-link-color:var(--mesh-primary);
--bs-link-color-rgb:var(--mesh-primary-rgb);
--bs-link-hover-color:var(--mesh-primary-dark);
--bs-link-hover-color-rgb:163,227,190;
--bs-link-hover-color-rgb:182,213,255;
}
body { background:var(--mesh-page); color:var(--mesh-text); }
.mesh-theme-toggle { flex-shrink:0; display:inline-flex; align-items:center; justify-content:center; width:34px; height:34px; border:1px solid #ffffff70; border-radius:6px; background:transparent; color:white; font:22px/1 system-ui,sans-serif; cursor:pointer; }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 172 KiB

+33 -33
View File
@@ -24,47 +24,47 @@
<style>
:root {
color-scheme:light;
--mesh-primary:#187346;
--mesh-primary-dark:#0f5132;
--mesh-primary-rgb:24,115,70;
--mesh-brand:#187346;
--mesh-brand-deep:#0f5132;
--mesh-primary:#245ea8;
--mesh-primary-dark:#19467f;
--mesh-primary-rgb:36,94,168;
--mesh-brand:#245ea8;
--mesh-brand-deep:#19467f;
--mesh-surface:#ffffff;
--mesh-text:#243247;
--mesh-soft:#eaf5ee;
--mesh-hover:#dceee2;
--mesh-border:#dce7df;
--mesh-page:#f5f9f6;
--mesh-stripe:#f7faf8;
--mesh-soft:#eaf1fb;
--mesh-hover:#dce8f8;
--mesh-border:#dce4ef;
--mesh-page:#f5f8fc;
--mesh-stripe:#f7f9fc;
--mesh-muted:#64748b;
--mesh-chat-stripe:#eef6f0;
--mesh-pulse-soft:#edf8f0;
--mesh-pulse-peak:#ccebd7;
--mesh-pulse-mid:#e2f3e8;
--mesh-chat-stripe:#eef3fb;
--mesh-pulse-soft:#edf4ff;
--mesh-pulse-peak:#c9defa;
--mesh-pulse-mid:#deebfc;
}
[data-bs-theme="dark"] {
color-scheme:dark;
--mesh-primary:#80cfa3;
--mesh-primary-dark:#a3e3be;
--mesh-primary-rgb:128,207,163;
--mesh-brand:#14532d;
--mesh-brand-deep:#0c3a1f;
--mesh-surface:#18231e;
--mesh-text:#e2ece5;
--mesh-soft:#203c2b;
--mesh-hover:#294c36;
--mesh-border:#34483c;
--mesh-page:#101914;
--mesh-stripe:#1c2a22;
--mesh-muted:#9faea6;
--mesh-chat-stripe:#203227;
--mesh-pulse-soft:#203c2b;
--mesh-pulse-peak:#356b49;
--mesh-pulse-mid:#294c36;
--mesh-primary:#8bbcff;
--mesh-primary-dark:#b6d5ff;
--mesh-primary-rgb:139,188,255;
--mesh-brand:#193d69;
--mesh-brand-deep:#112b4b;
--mesh-surface:#182335;
--mesh-text:#e2eaf6;
--mesh-soft:#203653;
--mesh-hover:#29486c;
--mesh-border:#34465f;
--mesh-page:#101925;
--mesh-stripe:#1c2a3d;
--mesh-muted:#a0aec2;
--mesh-chat-stripe:#20314a;
--mesh-pulse-soft:#203653;
--mesh-pulse-peak:#355d8e;
--mesh-pulse-mid:#29486c;
--bs-link-color:var(--mesh-primary);
--bs-link-color-rgb:var(--mesh-primary-rgb);
--bs-link-hover-color:var(--mesh-primary-dark);
--bs-link-hover-color-rgb:163,227,190;
--bs-link-hover-color-rgb:182,213,255;
}
body { background:var(--mesh-page); color:var(--mesh-text); }
.mesh-theme-toggle { flex-shrink:0; display:inline-flex; align-items:center; justify-content:center; width:34px; height:34px; border:1px solid #ffffff70; border-radius:6px; background:transparent; color:white; font:22px/1 system-ui,sans-serif; cursor:pointer; }
@@ -99,7 +99,7 @@ body { background:var(--mesh-page); color:var(--mesh-text); }
<!-- mesh-theme:end -->
</head>
<body>
<button class="mesh-theme-toggle" style="position:fixed;top:12px;right:12px;z-index:2000;background:#187346" type="button" data-theme-toggle aria-label="Switch to night mode" aria-pressed="false"><svg class="theme-icon theme-icon--sun" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M4.93 4.93l1.42 1.42m11.3 11.3 1.42 1.42M4.93 19.07l1.42-1.42m11.3-11.3 1.42-1.42"/></svg><svg class="theme-icon theme-icon--moon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20.9 13A9 9 0 0 1 11 3.1 9 9 0 1 0 20.9 13Z"/></svg></button>
<button class="mesh-theme-toggle" style="position:fixed;top:12px;right:12px;z-index:2000;background:#245ea8" type="button" data-theme-toggle aria-label="Switch to night mode" aria-pressed="false"><svg class="theme-icon theme-icon--sun" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M4.93 4.93l1.42 1.42m11.3 11.3 1.42 1.42M4.93 19.07l1.42-1.42m11.3-11.3 1.42-1.42"/></svg><svg class="theme-icon theme-icon--moon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20.9 13A9 9 0 0 1 11 3.1 9 9 0 1 0 20.9 13Z"/></svg></button>
<div id="map"></div>
<div id="legend"></div>
+33 -33
View File
@@ -38,47 +38,47 @@ body { margin: 0; font-family: monospace; background: #121212; color: #eee; }
<style>
:root {
color-scheme:light;
--mesh-primary:#187346;
--mesh-primary-dark:#0f5132;
--mesh-primary-rgb:24,115,70;
--mesh-brand:#187346;
--mesh-brand-deep:#0f5132;
--mesh-primary:#245ea8;
--mesh-primary-dark:#19467f;
--mesh-primary-rgb:36,94,168;
--mesh-brand:#245ea8;
--mesh-brand-deep:#19467f;
--mesh-surface:#ffffff;
--mesh-text:#243247;
--mesh-soft:#eaf5ee;
--mesh-hover:#dceee2;
--mesh-border:#dce7df;
--mesh-page:#f5f9f6;
--mesh-stripe:#f7faf8;
--mesh-soft:#eaf1fb;
--mesh-hover:#dce8f8;
--mesh-border:#dce4ef;
--mesh-page:#f5f8fc;
--mesh-stripe:#f7f9fc;
--mesh-muted:#64748b;
--mesh-chat-stripe:#eef6f0;
--mesh-pulse-soft:#edf8f0;
--mesh-pulse-peak:#ccebd7;
--mesh-pulse-mid:#e2f3e8;
--mesh-chat-stripe:#eef3fb;
--mesh-pulse-soft:#edf4ff;
--mesh-pulse-peak:#c9defa;
--mesh-pulse-mid:#deebfc;
}
[data-bs-theme="dark"] {
color-scheme:dark;
--mesh-primary:#80cfa3;
--mesh-primary-dark:#a3e3be;
--mesh-primary-rgb:128,207,163;
--mesh-brand:#14532d;
--mesh-brand-deep:#0c3a1f;
--mesh-surface:#18231e;
--mesh-text:#e2ece5;
--mesh-soft:#203c2b;
--mesh-hover:#294c36;
--mesh-border:#34483c;
--mesh-page:#101914;
--mesh-stripe:#1c2a22;
--mesh-muted:#9faea6;
--mesh-chat-stripe:#203227;
--mesh-pulse-soft:#203c2b;
--mesh-pulse-peak:#356b49;
--mesh-pulse-mid:#294c36;
--mesh-primary:#8bbcff;
--mesh-primary-dark:#b6d5ff;
--mesh-primary-rgb:139,188,255;
--mesh-brand:#193d69;
--mesh-brand-deep:#112b4b;
--mesh-surface:#182335;
--mesh-text:#e2eaf6;
--mesh-soft:#203653;
--mesh-hover:#29486c;
--mesh-border:#34465f;
--mesh-page:#101925;
--mesh-stripe:#1c2a3d;
--mesh-muted:#a0aec2;
--mesh-chat-stripe:#20314a;
--mesh-pulse-soft:#203653;
--mesh-pulse-peak:#355d8e;
--mesh-pulse-mid:#29486c;
--bs-link-color:var(--mesh-primary);
--bs-link-color-rgb:var(--mesh-primary-rgb);
--bs-link-hover-color:var(--mesh-primary-dark);
--bs-link-hover-color-rgb:163,227,190;
--bs-link-hover-color-rgb:182,213,255;
}
body { background:var(--mesh-page); color:var(--mesh-text); }
.mesh-theme-toggle { flex-shrink:0; display:inline-flex; align-items:center; justify-content:center; width:34px; height:34px; border:1px solid #ffffff70; border-radius:6px; background:transparent; color:white; font:22px/1 system-ui,sans-serif; cursor:pointer; }
@@ -113,7 +113,7 @@ body { background:var(--mesh-page); color:var(--mesh-text); }
<!-- mesh-theme:end -->
</head>
<body>
<button class="mesh-theme-toggle" style="position:fixed;top:12px;right:12px;z-index:2000;background:#187346" type="button" data-theme-toggle aria-label="Switch to night mode" aria-pressed="false"><svg class="theme-icon theme-icon--sun" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M4.93 4.93l1.42 1.42m11.3 11.3 1.42 1.42M4.93 19.07l1.42-1.42m11.3-11.3 1.42-1.42"/></svg><svg class="theme-icon theme-icon--moon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20.9 13A9 9 0 0 1 11 3.1 9 9 0 1 0 20.9 13Z"/></svg></button>
<button class="mesh-theme-toggle" style="position:fixed;top:12px;right:12px;z-index:2000;background:#245ea8" type="button" data-theme-toggle aria-label="Switch to night mode" aria-pressed="false"><svg class="theme-icon theme-icon--sun" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M4.93 4.93l1.42 1.42m11.3 11.3 1.42 1.42M4.93 19.07l1.42-1.42m11.3-11.3 1.42-1.42"/></svg><svg class="theme-icon theme-icon--moon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20.9 13A9 9 0 0 1 11 3.1 9 9 0 1 0 20.9 13Z"/></svg></button>
<div id="map"></div>
+5 -5
View File
@@ -1,10 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64" role="img" aria-labelledby="title">
<title id="title">Meshview: a mesh network through a magnifying glass</title>
<rect width="64" height="64" rx="15" fill="#eaf5ee"/>
<path d="M43 43 55 55" fill="none" stroke="#187346" stroke-width="7" stroke-linecap="round"/>
<circle cx="28" cy="28" r="19" fill="none" stroke="#187346" stroke-width="4"/>
<path d="m17 29 12-11 9 14-15 6-6-9 21 3" fill="none" stroke="#369361" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<g fill="#187346" stroke="#eaf5ee" stroke-width="1.5">
<rect width="64" height="64" rx="15" fill="#eaf1fb"/>
<path d="M43 43 55 55" fill="none" stroke="#245ea8" stroke-width="7" stroke-linecap="round"/>
<circle cx="28" cy="28" r="19" fill="none" stroke="#245ea8" stroke-width="4"/>
<path d="m17 29 12-11 9 14-15 6-6-9 21 3" fill="none" stroke="#5287cb" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<g fill="#245ea8" stroke="#eaf1fb" stroke-width="1.5">
<circle cx="17" cy="29" r="3.8"/>
<circle cx="29" cy="18" r="3.8"/>
<circle cx="38" cy="32" r="3.8"/>

Before

Width:  |  Height:  |  Size: 796 B

After

Width:  |  Height:  |  Size: 796 B

+7 -7
View File
@@ -1,17 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" width="396" height="88" viewBox="0 0 396 88" role="img" aria-labelledby="title desc">
<title id="title">Meshview</title>
<desc id="desc">Connected mesh nodes inside a green magnifying glass, alongside the Meshview wordmark.</desc>
<desc id="desc">Connected mesh nodes inside a blue magnifying glass, alongside the Meshview wordmark.</desc>
<g transform="translate(4 8) scale(1.125)">
<rect width="64" height="64" rx="15" fill="#eaf5ee"/>
<path d="M43 43 55 55" fill="none" stroke="#187346" stroke-width="7" stroke-linecap="round"/>
<circle cx="28" cy="28" r="19" fill="none" stroke="#187346" stroke-width="4"/>
<path d="m17 29 12-11 9 14-15 6-6-9 21 3" fill="none" stroke="#369361" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<g fill="#187346" stroke="#eaf5ee" stroke-width="1.5">
<rect width="64" height="64" rx="15" fill="#eaf1fb"/>
<path d="M43 43 55 55" fill="none" stroke="#245ea8" stroke-width="7" stroke-linecap="round"/>
<circle cx="28" cy="28" r="19" fill="none" stroke="#245ea8" stroke-width="4"/>
<path d="m17 29 12-11 9 14-15 6-6-9 21 3" fill="none" stroke="#5287cb" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<g fill="#245ea8" stroke="#eaf1fb" stroke-width="1.5">
<circle cx="17" cy="29" r="3.8"/>
<circle cx="29" cy="18" r="3.8"/>
<circle cx="38" cy="32" r="3.8"/>
<circle cx="23" cy="38" r="3.8"/>
</g>
</g>
<text x="94" y="61" fill="#143b29" font-family="Inter, system-ui, -apple-system, 'Segoe UI', sans-serif" font-size="51" font-weight="700" letter-spacing="-1.8">Meshview</text>
<text x="94" y="61" fill="#193d69" font-family="Inter, system-ui, -apple-system, 'Segoe UI', sans-serif" font-size="51" font-weight="700" letter-spacing="-1.8">Meshview</text>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

+5 -5
View File
@@ -20,9 +20,9 @@
// Neutral chart colors follow the theme; packet/route/series colors stay intact.
function chartOption(option) {
const palette = colors();
const text = new Set(['#333','#334155','#243247','#26364a','#e7eef7','#e2ece5']);
const muted = new Set(['#ccc','#64748b','#888','#9faea6','#8190a5']);
const border = new Set(['#aaa','#c3cfdf','#34483c','#dce7df']);
const text = new Set(['#333','#334155','#243247','#26364a','#e7eef7','#e2ece5','#e2eaf6']);
const muted = new Set(['#ccc','#64748b','#888','#9faea6','#8190a5','#a0aec2']);
const border = new Set(['#aaa','#c3cfdf','#34483c','#dce7df','#dce4ef','#34465f']);
function visit(value, key) {
if (Array.isArray(value)) return value.map(item => visit(item,key));
if (value && Object.getPrototypeOf(value) === Object.prototype) {
@@ -30,8 +30,8 @@
}
if (typeof value !== 'string') return value;
const hex = value.toLowerCase();
if (key === 'backgroundColor' && ['#fff','#ffffff','#18231e'].includes(hex)) return palette.surface;
if (['borderColor','textBorderColor'].includes(key) && ['#fff','#ffffff','#000','#18231e'].includes(hex)) return palette.surface;
if (key === 'backgroundColor' && ['#fff','#ffffff','#18231e','#182335'].includes(hex)) return palette.surface;
if (['borderColor','textBorderColor'].includes(key) && ['#fff','#ffffff','#000','#18231e','#182335'].includes(hex)) return palette.surface;
if (key === 'color' && text.has(hex)) return palette.text;
if (key === 'color' && muted.has(hex)) return palette.muted;
if (key === 'color' && border.has(hex)) return palette.border;
+6 -6
View File
@@ -59,10 +59,10 @@
--bs-link-color:var(--mesh-primary);
--bs-link-color-rgb:var(--mesh-primary-rgb);
--bs-link-hover-color:var(--mesh-primary-dark);
--bs-link-hover-color-rgb:15,81,50;
--bs-link-hover-color-rgb:25,70,127;
--bs-focus-ring-color:rgba(var(--mesh-primary-rgb),.25);
}
[data-bs-theme="dark"] { --bs-link-color:#75c99c; --bs-link-color-rgb:117,201,156; --bs-link-hover-color:#a3dfbc; --bs-link-hover-color-rgb:163,223,188; }
[data-bs-theme="dark"] { --bs-link-color:#8bbcff; --bs-link-color-rgb:139,188,255; --bs-link-hover-color:#b6d5ff; --bs-link-hover-color-rgb:182,213,255; }
.btn-primary {
--bs-btn-bg:var(--mesh-brand); --bs-btn-border-color:var(--mesh-brand);
--bs-btn-hover-bg:var(--mesh-brand-deep); --bs-btn-hover-border-color:var(--mesh-brand-deep);
@@ -100,13 +100,13 @@ input[type="checkbox"],input[type="radio"] { accent-color:var(--mesh-primary); }
@media(prefers-reduced-motion:reduce) {
.packet-arrival-glow > td { animation:none; background:var(--mesh-soft); }
}
.mesh-header { background:var(--mesh-brand); color:white; box-shadow:0 2px 8px #174b2d18; }
.mesh-header { background:var(--mesh-brand); color:white; box-shadow:0 2px 8px #193d6918; }
.mesh-header-inner { max-width:1600px; margin:auto; padding:0 28px; min-height:56px; display:flex; align-items:center; gap:32px; }
.mesh-brand { display:flex; align-items:center; gap:10px; font-size:19px; font-weight:700; color:white; text-decoration:none; flex-shrink:0; }
.mesh-brand:hover { color:white; }
.mesh-brand-icon { width:32px; height:32px; display:block; flex-shrink:0; }
#site-menu { display:flex; align-items:center; flex-wrap:wrap; gap:4px; }
#site-menu a { color:#e6f4ea; text-decoration:none; padding:10px 12px; border-radius:6px; font-size:14px; text-transform:capitalize; }
#site-menu a { color:#e6effb; text-decoration:none; padding:10px 12px; border-radius:6px; font-size:14px; text-transform:capitalize; }
#site-menu a:hover, #site-menu a.active { color:white; background:#ffffff26; }
.mesh-menu-toggle { display:none; color:white; background:none; border:1px solid #ffffff70; border-radius:5px; font-size:22px; }
.mesh-content { max-width:1600px; margin:0 auto; padding:28px; }
@@ -123,8 +123,8 @@ input[type="checkbox"],input[type="radio"] { accent-color:var(--mesh-primary); }
.mesh-metric { padding:20px 24px; background:var(--mesh-surface); border:1px solid var(--mesh-border); border-radius:9px; box-shadow:0 2px 4px var(--mesh-text)04; display:flex; flex-direction:column; gap:5px; }
.mesh-metric>span { font-size:13px; font-weight:500; color:var(--mesh-muted); }
.mesh-metric strong { font-size:30px; font-weight:650; color:var(--mesh-primary); font-variant-numeric:tabular-nums; }
.mesh-metric:nth-child(2) strong { color:#198754; }
.mesh-metric:nth-child(3) strong { color:#397955; }
.mesh-metric:nth-child(2) strong { color:var(--mesh-primary); }
.mesh-metric:nth-child(3) strong { color:var(--mesh-primary); }
.mesh-metric small { font-size:11px; color:var(--mesh-muted); }
.mesh-explorer { display:grid; grid-template-columns:290px minmax(0,1fr); gap:20px; }
.mesh-node-panel,.mesh-map-panel { background:var(--mesh-surface); border:1px solid var(--mesh-border); border-radius:9px; overflow:hidden; min-width:0; }
+3 -3
View File
@@ -16,7 +16,7 @@ body:has(#chat-container) .mesh-announcement { flex-shrink:0; }
.chat-filter { width:170px; font-size:12px; border-color:var(--mesh-border); }
.chat-search { width:210px; font-size:12px; border-color:var(--mesh-border); }
.chat-actions { display:flex; align-items:center; gap:8px; margin-left:auto; }
.chat-status { border-radius:20px; padding:4px 9px; background:#e8f5ee; color:#187346; font-size:11px; white-space:nowrap; }
.chat-status { border-radius:20px; padding:4px 9px; background:var(--mesh-soft); color:var(--mesh-primary); font-size:11px; white-space:nowrap; }
.chat-status[data-state="error"] { background:#fff0ed; color:#b23d2f; }
.chat-status[data-state="paused"],.chat-status[data-state="loading"] { background:#eef2f7; color:var(--mesh-muted); }
.chat-control { font-size:12px; background:var(--mesh-surface); border:1px solid var(--mesh-border); border-radius:5px; padding:5px 9px; color:var(--mesh-text); }
@@ -33,8 +33,8 @@ body:has(#chat-container) .mesh-announcement { flex-shrink:0; }
.chat-message { min-width:0; color:var(--mesh-text); overflow-wrap:anywhere; white-space:pre-wrap; }
.chat-meta { display:flex; align-items:center; gap:10px; font:11px system-ui,sans-serif; }
.chat-channel { background:#edf1f7; color:var(--mesh-muted); border-radius:4px; padding:2px 6px; max-width:130px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.chat-details { display:inline-flex; align-items:center; padding:4px 8px; border:1px solid #9dceb0; border-radius:5px; background:#e8f5ee; color:#187346; font-weight:600; text-decoration:none; white-space:nowrap; }
.chat-details:hover { color:#0f5132; background:#d1e7dd; border-color:#69aa85; }
.chat-details { display:inline-flex; align-items:center; padding:4px 8px; border:1px solid var(--mesh-border); border-radius:5px; background:var(--mesh-soft); color:var(--mesh-primary); font-weight:600; text-decoration:none; white-space:nowrap; }
.chat-details:hover { color:var(--mesh-primary-dark); background:var(--mesh-hover); border-color:var(--mesh-primary); }
.chat-details:focus-visible { outline:2px solid #198754; outline-offset:2px; }
.replying-to { display:block; border-left:2px solid var(--mesh-border); margin:4px 0; padding:2px 9px; color:var(--mesh-muted); font-size:11px; white-space:normal; }
.chat-empty { text-align:center; color:var(--mesh-muted); padding:48px 20px; font:13px system-ui,sans-serif; }
+15 -5
View File
@@ -98,6 +98,7 @@
<th data-translate-lang="role">Role <span class="sort-icon"></span></th>
<th data-translate-lang="last_lat">Last Latitude <span class="sort-icon"></span></th>
<th data-translate-lang="last_long">Last Longitude <span class="sort-icon"></span></th>
<th>Altitude (m) <span class="sort-icon"></span></th>
<th data-translate-lang="channel">Channel <span class="sort-icon"></span></th>
<th data-translate-lang="mqtt_gateway">MQTT <span class="sort-icon"></span></th>
<th data-translate-lang="last_seen">Last Seen <span class="sort-icon"></span></th>
@@ -106,7 +107,7 @@
</thead>
<tbody id="node-table-body">
<tr>
<td colspan="11" style="text-align:center; color:var(--mesh-muted);" data-translate-lang="loading_nodes">
<td colspan="12" style="text-align:center; color:var(--mesh-muted);" data-translate-lang="loading_nodes">
Loading nodes...
</td>
</tr>
@@ -169,7 +170,7 @@ const minStatusMs = 300;
const headers = document.querySelectorAll("thead th");
const keyMap = [
"short_name","long_name","hw_model","firmware","role",
"last_lat","last_long","channel","is_mqtt_gateway","last_seen_us"
"last_lat","last_long","last_altitude","channel","is_mqtt_gateway","last_seen_us"
];
function debounce(fn, delay = 250) {
@@ -300,7 +301,7 @@ document.addEventListener("DOMContentLoaded", async function() {
await loadNodesForActiveDays();
} catch (err) {
tbody.innerHTML = `<tr>
<td colspan="11" style="text-align:center; color:red;">
<td colspan="12" style="text-align:center; color:red;">
${nodelistTranslations.error_loading_nodes || "Error loading nodes"}
</td></tr>`;
setStatus("");
@@ -326,7 +327,7 @@ document.addEventListener("DOMContentLoaded", async function() {
} catch (err) {
console.error("Failed to reload nodes:", err);
tbody.innerHTML = `<tr>
<td colspan="11" style="text-align:center; color:red;">
<td colspan="12" style="text-align:center; color:red;">
${nodelistTranslations.error_loading_nodes || "Error loading nodes"}
</td></tr>`;
mobileList.innerHTML = "";
@@ -474,7 +475,7 @@ document.addEventListener("DOMContentLoaded", async function() {
if (!nodes.length) {
if (shouldRenderTable) {
tbody.innerHTML = `<tr>
<td colspan="11" style="text-align:center; color:var(--mesh-muted);">
<td colspan="12" style="text-align:center; color:var(--mesh-muted);">
${nodelistTranslations.no_nodes_found || "No nodes found"}
</td>
</tr>`;
@@ -503,6 +504,7 @@ document.addEventListener("DOMContentLoaded", async function() {
<td>${escapeHtml(node.role || "N/A")}</td>
<td>${node.last_lat ? (node.last_lat / 1e7).toFixed(7) : "N/A"}</td>
<td>${node.last_long ? (node.last_long / 1e7).toFixed(7) : "N/A"}</td>
<td>${node.last_altitude != null ? escapeHtml(String(node.last_altitude)) : "N/A"}</td>
<td>${escapeHtml(node.channel || "N/A")}</td>
<td>${node.is_mqtt_gateway ? (nodelistTranslations.yes || "Yes") : (nodelistTranslations.no || "No")}</td>
<td>${timeAgoFromMs(node.last_seen_ms)}</td>
@@ -534,6 +536,7 @@ document.addEventListener("DOMContentLoaded", async function() {
${node.last_lat ? (node.last_lat / 1e7).toFixed(5) : "N/A"},
${node.last_long ? (node.last_long / 1e7).toFixed(5) : "N/A"}
</div>
<div class="node-card-field"><b>Altitude:</b> ${node.last_altitude != null ? `${escapeHtml(String(node.last_altitude))} m above sea level` : "N/A"}</div>
<div class="node-card-field"><b>Channel:</b> ${escapeHtml(node.channel || "N/A")}</div>
<div class="node-card-field"><b>Last Seen:</b> ${timeAgoFromMs(node.last_seen_ms)}</div>
@@ -584,6 +587,7 @@ document.addEventListener("DOMContentLoaded", async function() {
node.firmware || "N/A", node.role || "N/A",
node.last_lat ? (node.last_lat / 1e7).toFixed(7) : "N/A",
node.last_long ? (node.last_long / 1e7).toFixed(7) : "N/A",
node.last_altitude ?? "N/A",
node.channel || "N/A",
node.is_mqtt_gateway ? (nodelistTranslations.yes || "Yes") : (nodelistTranslations.no || "No"),
timeAgoFromMs(node.last_seen_ms), isFavorite(node.node_id) ? "★" : "☆"
@@ -604,6 +608,12 @@ document.addEventListener("DOMContentLoaded", async function() {
let A = a[key];
let B = b[key];
if (key === "last_altitude") {
if (A == null && B == null) return 0;
if (A == null) return 1;
if (B == null) return -1;
}
if (key === "last_seen_us") {
A = A || 0;
B = B || 0;
+4 -4
View File
@@ -32,7 +32,7 @@
#altitude-router-map { flex:1; min-height:0; border-radius:6px; }
.altitude-router-icon { background:transparent; border:0; }
.altitude-router-icon svg { width:32px; height:32px; filter:drop-shadow(0 2px 3px #0005); }
.altitude-router-label { background:var(--mesh-surface); color:var(--mesh-text); border-color:var(--mesh-border); box-shadow:none; font-size:11px; }
.altitude-router-label { background:var(--mesh-surface); color:var(--mesh-text); border-color:var(--mesh-border); box-shadow:none; font-size:9px; line-height:1.2; padding:2px 4px; }
#modalChart { flex:1; min-height:0; width:100%; }
@media(max-width:1000px) { .stats-chart-grid { grid-template-columns:minmax(0,1fr); } }
@media(max-width:700px) { .summary-container { grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; } .summary-card { padding:16px; } .summary-count { font-size:26px; } .card-section { padding:14px; gap:8px; } .chart { height:320px; } }
@@ -123,7 +123,7 @@
<button class="export-btn" data-chart="chart_altitude">Export top 50 CSV</button>
<button id="altitude-map-button" type="button" disabled>Map top 50</button>
<div id="chart_altitude" class="chart"></div>
<p class="total-count">Latest reported altitude in meters above sea level. Only ROUTER, ROUTER_CLIENT, and ROUTER_LATE nodes at least 50 m above sea level are included. Click a bar to view the node.</p>
<p class="total-count">Latest reported altitude in meters above sea level. Only ROUTER, ROUTER_CLIENT, and ROUTER_LATE nodes at least 100 m above sea level are included. Click a bar to view the node.</p>
</div>
<!-- Packet Types Pie Chart with Channel Selector -->
@@ -325,7 +325,7 @@ let altitudeRows = [];
let altitudeExportRows = [];
function rankAltitudeNodes(nodes) {
return nodes
.filter(node => Number.isFinite(node.last_altitude) && node.last_altitude >= 50 && node.node_id != null
.filter(node => Number.isFinite(node.last_altitude) && node.last_altitude >= 100 && node.node_id != null
&& ["ROUTER", "ROUTER_CLIENT", "ROUTER_LATE"].includes((node.role || "").toUpperCase()))
.sort((a, b) => b.last_altitude - a.last_altitude || a.node_id - b.node_id);
}
@@ -362,7 +362,7 @@ async function loadAltitudeNodes(refreshNodes = false) {
}, true);
status.textContent = altitudeRows.length
? `Showing ${altitudeRows.length} nodes · highest first`
: "No routers have reported altitude of 50 m or more.";
: "No routers have reported altitude of 100 m or more.";
} catch (error) {
altitudeRows = [];
altitudeExportRows = [];
+32 -32
View File
@@ -1,47 +1,47 @@
<style>
:root {
color-scheme:light;
--mesh-primary:#187346;
--mesh-primary-dark:#0f5132;
--mesh-primary-rgb:24,115,70;
--mesh-brand:#187346;
--mesh-brand-deep:#0f5132;
--mesh-primary:#245ea8;
--mesh-primary-dark:#19467f;
--mesh-primary-rgb:36,94,168;
--mesh-brand:#245ea8;
--mesh-brand-deep:#19467f;
--mesh-surface:#ffffff;
--mesh-text:#243247;
--mesh-soft:#eaf5ee;
--mesh-hover:#dceee2;
--mesh-border:#dce7df;
--mesh-page:#f5f9f6;
--mesh-stripe:#f7faf8;
--mesh-soft:#eaf1fb;
--mesh-hover:#dce8f8;
--mesh-border:#dce4ef;
--mesh-page:#f5f8fc;
--mesh-stripe:#f7f9fc;
--mesh-muted:#64748b;
--mesh-chat-stripe:#eef6f0;
--mesh-pulse-soft:#edf8f0;
--mesh-pulse-peak:#ccebd7;
--mesh-pulse-mid:#e2f3e8;
--mesh-chat-stripe:#eef3fb;
--mesh-pulse-soft:#edf4ff;
--mesh-pulse-peak:#c9defa;
--mesh-pulse-mid:#deebfc;
}
[data-bs-theme="dark"] {
color-scheme:dark;
--mesh-primary:#80cfa3;
--mesh-primary-dark:#a3e3be;
--mesh-primary-rgb:128,207,163;
--mesh-brand:#14532d;
--mesh-brand-deep:#0c3a1f;
--mesh-surface:#18231e;
--mesh-text:#e2ece5;
--mesh-soft:#203c2b;
--mesh-hover:#294c36;
--mesh-border:#34483c;
--mesh-page:#101914;
--mesh-stripe:#1c2a22;
--mesh-muted:#9faea6;
--mesh-chat-stripe:#203227;
--mesh-pulse-soft:#203c2b;
--mesh-pulse-peak:#356b49;
--mesh-pulse-mid:#294c36;
--mesh-primary:#8bbcff;
--mesh-primary-dark:#b6d5ff;
--mesh-primary-rgb:139,188,255;
--mesh-brand:#193d69;
--mesh-brand-deep:#112b4b;
--mesh-surface:#182335;
--mesh-text:#e2eaf6;
--mesh-soft:#203653;
--mesh-hover:#29486c;
--mesh-border:#34465f;
--mesh-page:#101925;
--mesh-stripe:#1c2a3d;
--mesh-muted:#a0aec2;
--mesh-chat-stripe:#20314a;
--mesh-pulse-soft:#203653;
--mesh-pulse-peak:#355d8e;
--mesh-pulse-mid:#29486c;
--bs-link-color:var(--mesh-primary);
--bs-link-color-rgb:var(--mesh-primary-rgb);
--bs-link-hover-color:var(--mesh-primary-dark);
--bs-link-hover-color-rgb:163,227,190;
--bs-link-hover-color-rgb:182,213,255;
}
body { background:var(--mesh-page); color:var(--mesh-text); }
.mesh-theme-toggle { flex-shrink:0; display:inline-flex; align-items:center; justify-content:center; width:34px; height:34px; border:1px solid #ffffff70; border-radius:6px; background:transparent; color:white; font:22px/1 system-ui,sans-serif; cursor:pointer; }