fix: replace relay dropdown with direct dialog on click
Some checks failed
Build Release Binaries / build-amd64 (push) Failing after 3m53s
Some checks failed
Build Release Binaries / build-amd64 (push) Failing after 3m53s
- Click relay button opens Manage Relays dialog directly (no dropdown) - Click a relay in the dialog to select it (highlighted with accent border) - × button to delete, Add Relay button to add new - Removed all dropdown menu code and CSS Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,17 +14,11 @@
|
|||||||
<p class="subtitle">Encrypted Voice</p>
|
<p class="subtitle">Encrypted Voice</p>
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<label>Relay
|
<label>Relay
|
||||||
<div class="relay-dropdown-wrap">
|
<button id="relay-selected" class="relay-selected" type="button">
|
||||||
<button id="relay-selected" class="relay-selected" type="button">
|
<span id="relay-dot" class="dot"></span>
|
||||||
<span id="relay-dot" class="dot"></span>
|
<span id="relay-label">Select relay...</span>
|
||||||
<span id="relay-label">Select relay...</span>
|
<span class="arrow">⚙</span>
|
||||||
<span class="arrow">▾</span>
|
</button>
|
||||||
</button>
|
|
||||||
<div id="relay-menu" class="relay-menu hidden">
|
|
||||||
<div id="relay-list"></div>
|
|
||||||
<button id="relay-manage-btn" class="relay-manage-btn" type="button">Manage Relays...</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</label>
|
</label>
|
||||||
<label>Room
|
<label>Room
|
||||||
<input id="room" type="text" value="android" />
|
<input id="room" type="text" value="android" />
|
||||||
|
|||||||
@@ -23,13 +23,10 @@ const statsDiv = document.getElementById("stats")!;
|
|||||||
const myFingerprintEl = document.getElementById("my-fingerprint")!;
|
const myFingerprintEl = document.getElementById("my-fingerprint")!;
|
||||||
const recentRoomsDiv = document.getElementById("recent-rooms")!;
|
const recentRoomsDiv = document.getElementById("recent-rooms")!;
|
||||||
|
|
||||||
// Relay dropdown
|
// Relay button
|
||||||
const relaySelected = document.getElementById("relay-selected")!;
|
const relaySelected = document.getElementById("relay-selected")!;
|
||||||
const relayDot = document.getElementById("relay-dot")!;
|
const relayDot = document.getElementById("relay-dot")!;
|
||||||
const relayLabel = document.getElementById("relay-label")!;
|
const relayLabel = document.getElementById("relay-label")!;
|
||||||
const relayMenu = document.getElementById("relay-menu")!;
|
|
||||||
const relayList = document.getElementById("relay-list")!;
|
|
||||||
const relayManageBtn = document.getElementById("relay-manage-btn")!;
|
|
||||||
|
|
||||||
// Relay dialog
|
// Relay dialog
|
||||||
const relayDialog = document.getElementById("relay-dialog")!;
|
const relayDialog = document.getElementById("relay-dialog")!;
|
||||||
@@ -126,7 +123,7 @@ function applySettings() {
|
|||||||
aliasInput.value = s.alias;
|
aliasInput.value = s.alias;
|
||||||
osAecCheckbox.checked = s.osAec;
|
osAecCheckbox.checked = s.osAec;
|
||||||
renderRecentRooms(s.recentRooms);
|
renderRecentRooms(s.recentRooms);
|
||||||
renderRelayDropdown();
|
renderRelayButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Relay dropdown ──
|
// ── Relay dropdown ──
|
||||||
@@ -143,7 +140,7 @@ function rttText(rtt: number | null | undefined): string {
|
|||||||
return `${rtt}ms`;
|
return `${rtt}ms`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderRelayDropdown() {
|
function renderRelayButton() {
|
||||||
const s = loadSettings();
|
const s = loadSettings();
|
||||||
const sel = s.relays[s.selectedRelay];
|
const sel = s.relays[s.selectedRelay];
|
||||||
if (sel) {
|
if (sel) {
|
||||||
@@ -153,46 +150,9 @@ function renderRelayDropdown() {
|
|||||||
relayDot.className = "dot gray";
|
relayDot.className = "dot gray";
|
||||||
relayLabel.textContent = "No relay configured";
|
relayLabel.textContent = "No relay configured";
|
||||||
}
|
}
|
||||||
// Menu items
|
|
||||||
relayList.innerHTML = s.relays
|
|
||||||
.map((r, i) => `
|
|
||||||
<div class="relay-menu-item ${i === s.selectedRelay ? "active" : ""}" data-idx="${i}">
|
|
||||||
<span class="dot ${dotClass(r.rtt)}"></span>
|
|
||||||
<div class="relay-info">
|
|
||||||
<div class="relay-name">${escapeHtml(r.name)}</div>
|
|
||||||
<div class="relay-addr">${escapeHtml(r.address)}</div>
|
|
||||||
</div>
|
|
||||||
<span class="relay-rtt">${rttText(r.rtt)}</span>
|
|
||||||
</div>`)
|
|
||||||
.join("");
|
|
||||||
|
|
||||||
relayList.querySelectorAll(".relay-menu-item").forEach((el) => {
|
|
||||||
el.addEventListener("click", () => {
|
|
||||||
const idx = parseInt((el as HTMLElement).dataset.idx || "0");
|
|
||||||
const s = loadSettings();
|
|
||||||
s.selectedRelay = idx;
|
|
||||||
saveSettingsObj(s);
|
|
||||||
relayMenu.classList.add("hidden");
|
|
||||||
renderRelayDropdown();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
relaySelected.addEventListener("click", (e) => {
|
relaySelected.addEventListener("click", () => openRelayDialog());
|
||||||
e.stopPropagation();
|
|
||||||
relayMenu.classList.toggle("hidden");
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener("click", () => {
|
|
||||||
relayMenu.classList.add("hidden");
|
|
||||||
});
|
|
||||||
|
|
||||||
relayMenu.addEventListener("click", (e) => e.stopPropagation());
|
|
||||||
|
|
||||||
relayManageBtn.addEventListener("click", () => {
|
|
||||||
relayMenu.classList.add("hidden");
|
|
||||||
openRelayDialog();
|
|
||||||
});
|
|
||||||
|
|
||||||
// ── Relay manage dialog ──
|
// ── Relay manage dialog ──
|
||||||
function openRelayDialog() {
|
function openRelayDialog() {
|
||||||
@@ -204,14 +164,14 @@ function openRelayDialog() {
|
|||||||
|
|
||||||
function closeRelayDialog() {
|
function closeRelayDialog() {
|
||||||
relayDialog.classList.add("hidden");
|
relayDialog.classList.add("hidden");
|
||||||
renderRelayDropdown();
|
renderRelayButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderRelayDialogList() {
|
function renderRelayDialogList() {
|
||||||
const s = loadSettings();
|
const s = loadSettings();
|
||||||
relayDialogList.innerHTML = s.relays
|
relayDialogList.innerHTML = s.relays
|
||||||
.map((r, i) => `
|
.map((r, i) => `
|
||||||
<div class="relay-dialog-item" data-idx="${i}">
|
<div class="relay-dialog-item ${i === s.selectedRelay ? "selected" : ""}" data-idx="${i}">
|
||||||
<span class="dot ${dotClass(r.rtt)}"></span>
|
<span class="dot ${dotClass(r.rtt)}"></span>
|
||||||
<div class="relay-info">
|
<div class="relay-info">
|
||||||
<div class="relay-name">${escapeHtml(r.name)}</div>
|
<div class="relay-name">${escapeHtml(r.name)}</div>
|
||||||
@@ -222,6 +182,19 @@ function renderRelayDialogList() {
|
|||||||
</div>`)
|
</div>`)
|
||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
|
// Click item to select
|
||||||
|
relayDialogList.querySelectorAll(".relay-dialog-item").forEach((el) => {
|
||||||
|
el.addEventListener("click", () => {
|
||||||
|
const idx = parseInt((el as HTMLElement).dataset.idx || "0");
|
||||||
|
const s = loadSettings();
|
||||||
|
s.selectedRelay = idx;
|
||||||
|
saveSettingsObj(s);
|
||||||
|
renderRelayDialogList();
|
||||||
|
renderRelayButton();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Click × to delete
|
||||||
relayDialogList.querySelectorAll(".remove").forEach((btn) => {
|
relayDialogList.querySelectorAll(".remove").forEach((btn) => {
|
||||||
btn.addEventListener("click", (e) => {
|
btn.addEventListener("click", (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -231,6 +204,7 @@ function renderRelayDialogList() {
|
|||||||
if (s.selectedRelay >= s.relays.length) s.selectedRelay = Math.max(0, s.relays.length - 1);
|
if (s.selectedRelay >= s.relays.length) s.selectedRelay = Math.max(0, s.relays.length - 1);
|
||||||
saveSettingsObj(s);
|
saveSettingsObj(s);
|
||||||
renderRelayDialogList();
|
renderRelayDialogList();
|
||||||
|
renderRelayButton();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -264,7 +238,7 @@ async function pingAllRelays() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
saveSettingsObj(s);
|
saveSettingsObj(s);
|
||||||
renderRelayDropdown();
|
renderRelayButton();
|
||||||
// Also update dialog if open
|
// Also update dialog if open
|
||||||
if (!relayDialog.classList.contains("hidden")) {
|
if (!relayDialog.classList.contains("hidden")) {
|
||||||
renderRelayDialogList();
|
renderRelayDialogList();
|
||||||
@@ -286,7 +260,7 @@ function renderRecentRooms(rooms: RecentRoom[]) {
|
|||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
s.selectedRelay = idx;
|
s.selectedRelay = idx;
|
||||||
saveSettingsObj(s);
|
saveSettingsObj(s);
|
||||||
renderRelayDropdown();
|
renderRelayButton();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -89,11 +89,7 @@ body {
|
|||||||
border-color: var(--accent);
|
border-color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Relay dropdown ── */
|
/* ── Relay button ── */
|
||||||
.relay-dropdown-wrap {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.relay-selected {
|
.relay-selected {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -130,54 +126,6 @@ body {
|
|||||||
.dot.red { background: var(--red); }
|
.dot.red { background: var(--red); }
|
||||||
.dot.gray { background: #555; }
|
.dot.gray { background: #555; }
|
||||||
|
|
||||||
.relay-menu {
|
|
||||||
position: absolute;
|
|
||||||
top: calc(100% + 4px);
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
background: var(--surface);
|
|
||||||
border: 1px solid #444;
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
z-index: 50;
|
|
||||||
box-shadow: 0 8px 24px rgba(0,0,0,0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.relay-menu-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 10px 12px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 13px;
|
|
||||||
transition: background 0.1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.relay-menu-item:hover { background: var(--surface2); }
|
|
||||||
.relay-menu-item.active { background: var(--primary); }
|
|
||||||
|
|
||||||
.relay-menu-item .dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
|
||||||
|
|
||||||
.relay-menu-item .relay-info { flex: 1; min-width: 0; overflow: hidden; }
|
|
||||||
.relay-menu-item .relay-name { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
||||||
.relay-menu-item .relay-addr { font-size: 11px; color: var(--text-dim); font-family: monospace; overflow: hidden; text-overflow: ellipsis; }
|
|
||||||
.relay-menu-item .relay-rtt { font-size: 11px; color: var(--text-dim); white-space: nowrap; }
|
|
||||||
|
|
||||||
.relay-manage-btn {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
padding: 10px;
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
border-top: 1px solid #333;
|
|
||||||
color: var(--accent);
|
|
||||||
font-size: 13px;
|
|
||||||
cursor: pointer;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.relay-manage-btn:hover { background: var(--surface2); }
|
|
||||||
|
|
||||||
/* ── Relay dialog ── */
|
/* ── Relay dialog ── */
|
||||||
#relay-dialog {
|
#relay-dialog {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -214,6 +162,10 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.relay-dialog-item .dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
.relay-dialog-item .dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
||||||
|
.relay-dialog-item { cursor: pointer; transition: background 0.1s; }
|
||||||
|
.relay-dialog-item:hover { background: var(--surface2); }
|
||||||
|
.relay-dialog-item.selected { background: var(--primary); border: 1px solid var(--accent); }
|
||||||
|
|
||||||
.relay-dialog-item .relay-info { flex: 1; min-width: 0; overflow: hidden; }
|
.relay-dialog-item .relay-info { flex: 1; min-width: 0; overflow: hidden; }
|
||||||
.relay-dialog-item .relay-name { font-size: 13px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
.relay-dialog-item .relay-name { font-size: 13px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
.relay-dialog-item .relay-addr { font-size: 11px; color: var(--text-dim); font-family: monospace; overflow: hidden; text-overflow: ellipsis; }
|
.relay-dialog-item .relay-addr { font-size: 11px; color: var(--text-dim); font-family: monospace; overflow: hidden; text-overflow: ellipsis; }
|
||||||
|
|||||||
Reference in New Issue
Block a user