From eff65c198a26d8b31b2e62daf62f1f58f61fceca Mon Sep 17 00:00:00 2001 From: Melissa LeBlanc-Williams Date: Wed, 22 Jul 2026 10:41:03 -0700 Subject: [PATCH] Add connection type indicator --- js/script.js | 72 ++++++++++++++++++++++++++++++--- sass/layout/_header.scss | 25 ++++++++++++ sass/layout/_header_mobile.scss | 11 +++++ 3 files changed, 102 insertions(+), 6 deletions(-) diff --git a/js/script.js b/js/script.js index c1a9d9c..e703fe4 100644 --- a/js/script.js +++ b/js/script.js @@ -52,7 +52,7 @@ const btnRestart = document.querySelector('.btn-restart'); const btnHalt = document.querySelector('.btn-halt'); const btnPlotter = document.querySelector('.btn-plotter'); const btnClear = document.querySelector('.btn-clear'); -const btnConnect = document.querySelectorAll('.btn-connect'); +let btnConnect = document.querySelectorAll('.btn-connect'); const btnNew = document.querySelectorAll('.btn-new'); const btnOpen = document.querySelectorAll('.btn-open'); const btnFormat = document.querySelectorAll('.btn-format'); @@ -77,6 +77,21 @@ const MAX_EDITOR_FONT_SIZE = 48; // disconnect, we prefer the last backend over re-prompting for one. const LAST_BACKEND_KEY = "webeditor.lastBackend"; +const CONNECTION_DETAILS = { + [CONNTYPE.Web]: { + label: "WiFi", + iconClass: "fa-solid fa-wifi", + }, + [CONNTYPE.Ble]: { + label: "Bluetooth", + iconClass: "fa-brands fa-bluetooth-b", + }, + [CONNTYPE.Usb]: { + label: "USB", + iconClass: "fa-brands fa-usb", + }, +}; + function getLastBackend() { try { const name = window.localStorage.getItem(LAST_BACKEND_KEY); @@ -100,6 +115,43 @@ function rememberLastBackend(workflowType) { } } +function getConnectionIndicatorType() { + if (workflow && workflow.type !== CONNTYPE.None) { + return workflow.type; + } + return getLastBackend(); +} + +function getConnectButtonContents(isConnected) { + const action = isConnected ? "Disconnect" : "Connect"; + const connectionType = getConnectionIndicatorType(); + const details = CONNECTION_DETAILS[connectionType]; + + if (!details) { + return { + html: action, + label: action, + title: action, + }; + } + + const status = isConnected ? "Connected via" : "Last connection"; + const actionLabel = isConnected + ? `Disconnect ${details.label}` + : `Connect using ${details.label}`; + + return { + html: ` ${action}`, + label: actionLabel, + title: `${status}: ${details.label}`, + }; +} + +function getConnectButtons() { + btnConnect = document.querySelectorAll('.btn-connect'); + return btnConnect; +} + const editorTheme = EditorView.theme({}, {dark: getCssVar('editor-theme-dark').trim() === '1'}); const editorFontSizeCompartment = new Compartment(); @@ -629,6 +681,7 @@ async function loadWorkflow(workflowType = null) { } workflow = workflows[workflowType]; rememberLastBackend(workflowType); + updateUIConnected(false); // Initialize the workflow await workflow.init({ terminal: state.terminal, @@ -657,6 +710,7 @@ async function loadWorkflow(workflowType = null) { } // Unload workflow workflow = null; + updateUIConnected(false); } } @@ -723,10 +777,13 @@ async function debugLog(msg) { } function updateUIConnected(isConnected) { + const buttonState = getConnectButtonContents(isConnected); if (isConnected) { // Set to Connected State - btnConnect.forEach((element) => { - element.innerHTML = "Disconnect"; + getConnectButtons().forEach((element) => { + element.innerHTML = buttonState.html; + element.setAttribute("aria-label", buttonState.label); + element.title = buttonState.title; element.disabled = false; }); if (workflow.showInfo !== undefined) { @@ -734,8 +791,10 @@ function updateUIConnected(isConnected) { } } else { // Set to Disconnected State - btnConnect.forEach((element) => { - element.innerHTML = "Connect"; + getConnectButtons().forEach((element) => { + element.innerHTML = buttonState.html; + element.setAttribute("aria-label", buttonState.label); + element.title = buttonState.title; element.disabled = false; }); btnInfo.disabled = true; @@ -1046,7 +1105,8 @@ function applySettings() { document.addEventListener('DOMContentLoaded', async (event) => { await setupXterm(); applySettings(); - btnConnect.forEach((element) => { + updateUIConnected(false); + getConnectButtons().forEach((element) => { element.addEventListener('click', async function(e) { e.preventDefault(); e.stopPropagation(); diff --git a/sass/layout/_header.scss b/sass/layout/_header.scss index 30d1fea..144dea8 100644 --- a/sass/layout/_header.scss +++ b/sass/layout/_header.scss @@ -107,10 +107,35 @@ & { background-color: transparent; margin: 0; + align-items: center; + display: inline-flex; + gap: 8px; + justify-content: center; + min-width: 118px; } } } +.connection-indicator { + align-items: center; + display: inline-flex; + gap: 5px; + white-space: nowrap; + + i { + font-size: 16px; + line-height: 1; + } +} + +.connection-label { + font-size: 13px; +} + +.connect-action { + white-space: nowrap; +} + .site-navigation { padding: 0 0 10px 0; font-size: 18px; diff --git a/sass/layout/_header_mobile.scss b/sass/layout/_header_mobile.scss index b3ed46a..be151e1 100644 --- a/sass/layout/_header_mobile.scss +++ b/sass/layout/_header_mobile.scss @@ -108,4 +108,15 @@ #mobile-editor-bar { display: block !important; } + + #mobile-header { + .get-started button { + gap: 6px; + min-width: 94px; + } + + .connection-label { + display: none; + } + } }