diff --git a/Model.js b/Model.js index c9d82b5..237a21f 100644 --- a/Model.js +++ b/Model.js @@ -57,11 +57,25 @@ function osIcon(os) { return "󰟀" } +// Stock returned the nickname alone, which on a multi-tailnet setup is the +// least useful field — "andre" and "pastilhas" say nothing about which tailnet +// you would be switching to. `tailscale switch --list --json` carries both, so +// show the tailnet with the account in parentheses: +// +// headscale.pertento.ai (andre) +// offscale.pastilhas.dev (pastilhas) +// +// Falls back through the same chain as before when a field is absent, so a +// profile with no tailnet still renders something meaningful. function accountLabel(account) { if (!account) return "Unknown account" - if (account.nickname) return String(account.nickname) - if (account.tailnet) return String(account.tailnet) - if (account.account) return String(account.account) + + var tailnet = String(account.tailnet || "").trim() + var who = String(account.account || account.nickname || "").trim() + + if (tailnet !== "" && who !== "") return tailnet + " (" + who + ")" + if (tailnet !== "") return tailnet + if (who !== "") return who return String(account.id || "Unknown account") } @@ -292,6 +306,19 @@ function parseAccounts(raw) { if (account.selected === true) selected = account } } + + // Active connection first, everything else in the order the CLI listed it. + // Sorted here rather than in the view so the Repeater and the keyboard + // cursor (accountIndex) index into the same ordering — sorting only at + // render time would leave j/k selecting a different row than the one + // highlighted. Array.sort is stable, so the unselected profiles keep their + // relative order. + next.sort(function(left, right) { + var l = left.selected === true ? 0 : 1 + var r = right.selected === true ? 0 : 1 + return l - r + }) + return { accounts: next, selectedAccountId: selected ? String(selected.id || "") : "", diff --git a/Panel.qml b/Panel.qml index db2205f..e377d83 100644 --- a/Panel.qml +++ b/Panel.qml @@ -854,7 +854,12 @@ Panel { current: selectedAccount foreground: root.foreground fill: root.hoverFill - currentFill: root.selectedFill + // No filled background on the active connection — it reads as the brand + // yellow on its label instead (see the Text below). `current` also selects + // the "selected" border spec, but the theme sets selected-border-width to + // 0, so clearing the fill leaves nothing drawn. Hover still highlights + // through `fill`, so the row keeps its affordance. + currentFill: "transparent" implicitHeight: accountInner.implicitHeight + Style.spacing.xl @@ -888,7 +893,9 @@ Panel { Text { text: accountRow.accountText - color: root.foreground + // The active connection is marked by colour rather than a filled + // background: brand yellow here, themed white for the others. + color: accountRow.selectedAccount ? root.accent : root.foreground font.family: root.fontFamily font.pixelSize: Style.font.body font.bold: accountRow.selectedAccount