Web: add meshcoretel.ru profile link button next to public key

Adds a hidden `ℹ` button (meshcoretelProfileBtn) in the Public Key
field of the Info panel.  After initApp() finishes loading the
"Loading info..." section, the public key value is read from the
DOM and validated against /^[0-9A-F]{64}$/.  If it passes, an onclick
handler is attached that opens https://meshcoretel.ru/<PUBLIC_KEY>
in a new tab, and the button is made visible.  The button remains
hidden if the key fails to load or does not match the expected 64-char
uppercase hex pattern, so the UI degrades gracefully on any firmware
that does not return a valid public key.

The container div is changed from fieldline (2-column grid: 1fr auto)
to inline-actions (3-column grid: minmax(0,1fr) auto auto) to accommodate
the second action button without wrapping.
此提交包含在:
Valentin V. Bartenev
2026-05-17 15:40:10 +03:00
父節點 7378666416
當前提交 8a0d04fa86
+8 -1
查看文件
@@ -656,9 +656,10 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
</div>
<div class="field-card">
<label class="label" for="publicKey">Public Key</label>
<div class="fieldline">
<div class="inline-actions">
<input id="publicKey" readonly disabled>
<button id="copyPublicKeyBtn" class="iconbtn" title="Copy public key">&#x2398;</button>
<button id="meshcoretelProfileBtn" class="iconbtn" title="View on meshcoretel.ru" style="display:none">&#x2139;</button>
</div>
</div>
</div>
@@ -2723,6 +2724,12 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
() => loadField("clock", "clockUtc", null, quiet),
() => loadField("get public.key", "publicKey", "uppercase", quiet)
]);
const pubKeyValue = document.getElementById("publicKey").value.trim();
const profileBtn = document.getElementById("meshcoretelProfileBtn");
if (profileBtn && /^[0-9A-F]{64}$/.test(pubKeyValue)) {
profileBtn.onclick = () => window.open("https://meshcoretel.ru/" + encodeURIComponent(pubKeyValue), "_blank", "noopener,noreferrer");
profileBtn.style.display = "";
}
await loadSection("Loading repeater settings...", [
() => loadField("get name", "nodeName", null, quiet),
() => loadField("get lat", "nodeLat", null, quiet),