Move DM relay settings into DM settings popover

This commit is contained in:
thePR0M3TH3AN committed 2026-01-29 11:52:41 -05:00
1 parent 73399751e0
commit c4a00653f4
4 files changed
+156 -76

No files matched your search

-44
View File
@@ -1355,50 +1355,6 @@
role="tabpanel"
aria-labelledby="profileNavMessages"
>
<div id="profileMessagesRelayPanel" class="card space-y-4 p-5">
<div class="space-y-2">
<h3 class="text-base font-semibold text-text">DM relay hints</h3>
<p class="text-sm text-muted">
Publish relay hints for direct messages as <span class="font-medium">kind:10050</span> events. Use WSS-only relay URLs so encrypted DM delivery stays secure.
</p>
</div>
<div class="flex flex-col gap-3 sm:flex-row sm:items-end">
<label class="flex-1 text-sm text-muted-strong" for="profileMessagesRelayInput">
<span class="mb-2 block font-medium">Add a DM relay</span>
<input
id="profileMessagesRelayInput"
type="text"
inputmode="url"
autocomplete="off"
class="input"
placeholder="wss://relay.example.com"
/>
</label>
<button
id="profileMessagesRelayAdd"
type="button"
class="btn focus-ring"
>
Add relay
</button>
</div>
<div class="flex flex-wrap items-center gap-2">
<button
id="profileMessagesRelayPublish"
type="button"
class="btn-ghost focus-ring text-xs"
>
Publish relay hints
</button>
<span
id="profileMessagesRelayStatus"
class="text-xs text-muted"
role="status"
aria-live="polite"
></span>
</div>
<ul id="profileMessagesRelayList" class="grid-stack" data-orientation="vertical"></ul>
</div>
<div id="dmAppShellMount"></div>
</section>
<section
+12 -2
View File
@@ -2,6 +2,7 @@ import { Composer } from "./Composer.js";
import { ConversationList } from "./ConversationList.js";
import { MessageThread } from "./MessageThread.js";
import { DMPrivacySettings } from "./DMPrivacySettings.js";
import { DMRelaySettings } from "./DMRelaySettings.js";
import { aggregateZapTotals } from "./zapHelpers.js";
import { createZapInterface } from "./ZapInterface.js";
@@ -136,6 +137,7 @@ export class AppShell {
onToggleTypingIndicators,
onRefreshConversations,
onBack,
onOpenSettings,
} = {}) {
if (!doc) {
throw new Error("AppShell requires a document reference.");
@@ -182,15 +184,23 @@ export class AppShell {
popover.remove();
return;
}
popover = DMPrivacySettings({
popover = createElement(doc, "div", "dm-settings-popover absolute z-50 right-4 top-12 flex flex-col gap-4");
const privacySettings = DMPrivacySettings({
document: doc,
readReceiptsEnabled: dmPrivacySettings.readReceiptsEnabled,
typingIndicatorsEnabled: dmPrivacySettings.typingIndicatorsEnabled,
onToggleReadReceipts,
onToggleTypingIndicators,
});
popover.classList.add("dm-settings-popover", "absolute", "z-50", "right-4", "top-12", "bg-surface", "border", "border-border", "rounded-xl");
popover.appendChild(privacySettings);
const relaySettings = DMRelaySettings({ document: doc });
popover.appendChild(relaySettings);
sidebarHeader.appendChild(popover);
if (typeof onOpenSettings === "function") {
onOpenSettings(popover);
}
const closeHandler = (event) => {
if (!popover.contains(event.target) && event.target !== settingsBtn && !settingsBtn.contains(event.target)) {
+80
View File
@@ -0,0 +1,80 @@
export function DMRelaySettings({ document: doc } = {}) {
if (!doc) {
throw new Error("DMRelaySettings requires a document reference.");
}
const root = doc.createElement("div");
root.id = "profileMessagesRelayPanel";
root.className = "dm-relay-settings card space-y-4 p-5";
const heading = doc.createElement("div");
heading.className = "space-y-2";
const title = doc.createElement("h3");
title.className = "text-base font-semibold text-text";
title.textContent = "DM relay hints";
heading.appendChild(title);
const description = doc.createElement("p");
description.className = "text-sm text-muted";
description.innerHTML =
'Publish relay hints for direct messages as <span class="font-medium">kind:10050</span> events. Use WSS-only relay URLs so encrypted DM delivery stays secure.';
heading.appendChild(description);
root.appendChild(heading);
const addRow = doc.createElement("div");
addRow.className = "flex flex-col gap-3 sm:flex-row sm:items-end";
const label = doc.createElement("label");
label.className = "flex-1 text-sm text-muted-strong";
label.setAttribute("for", "profileMessagesRelayInput");
const labelTitle = doc.createElement("span");
labelTitle.className = "mb-2 block font-medium";
labelTitle.textContent = "Add a DM relay";
label.appendChild(labelTitle);
const input = doc.createElement("input");
input.id = "profileMessagesRelayInput";
input.type = "text";
input.inputMode = "url";
input.autocomplete = "off";
input.className = "input";
input.placeholder = "wss://relay.example.com";
label.appendChild(input);
addRow.appendChild(label);
const addButton = doc.createElement("button");
addButton.id = "profileMessagesRelayAdd";
addButton.type = "button";
addButton.className = "btn focus-ring";
addButton.textContent = "Add relay";
addRow.appendChild(addButton);
root.appendChild(addRow);
const publishRow = doc.createElement("div");
publishRow.className = "flex flex-wrap items-center gap-2";
const publishButton = doc.createElement("button");
publishButton.id = "profileMessagesRelayPublish";
publishButton.type = "button";
publishButton.className = "btn-ghost focus-ring text-xs";
publishButton.textContent = "Publish relay hints";
publishRow.appendChild(publishButton);
const status = doc.createElement("span");
status.id = "profileMessagesRelayStatus";
status.className = "text-xs text-muted";
status.setAttribute("role", "status");
status.setAttribute("aria-live", "polite");
publishRow.appendChild(status);
root.appendChild(publishRow);
const list = doc.createElement("ul");
list.id = "profileMessagesRelayList";
list.className = "grid-stack";
list.dataset.orientation = "vertical";
root.appendChild(list);
return root;
}
+64 -30
View File
@@ -1646,16 +1646,7 @@ export class ProfileModalController {
document.getElementById("profileMessagesPrivacyToggle") || null;
this.profileMessagesPrivacyMode =
document.getElementById("profileMessagesPrivacyMode") || null;
this.profileMessagesRelayList =
document.getElementById("profileMessagesRelayList") || null;
this.profileMessagesRelayInput =
document.getElementById("profileMessagesRelayInput") || null;
this.profileMessagesRelayAddButton =
document.getElementById("profileMessagesRelayAdd") || null;
this.profileMessagesRelayPublishButton =
document.getElementById("profileMessagesRelayPublish") || null;
this.profileMessagesRelayStatus =
document.getElementById("profileMessagesRelayStatus") || null;
this.cacheDmRelayElements();
this.profileMessagesUnreadDot =
document.getElementById("profileMessagesUnreadDot") || null;
this.dmAppShellContainer =
@@ -2251,6 +2242,63 @@ export class ProfileModalController {
setLinkPreviewAutoFetch(Boolean(enabled));
}
cacheDmRelayElements() {
this.profileMessagesRelayList =
document.getElementById("profileMessagesRelayList") || null;
this.profileMessagesRelayInput =
document.getElementById("profileMessagesRelayInput") || null;
this.profileMessagesRelayAddButton =
document.getElementById("profileMessagesRelayAdd") || null;
this.profileMessagesRelayPublishButton =
document.getElementById("profileMessagesRelayPublish") || null;
this.profileMessagesRelayStatus =
document.getElementById("profileMessagesRelayStatus") || null;
}
bindDmRelayControls() {
const bindOnce = (element, eventName, handler, key) => {
if (!(element instanceof HTMLElement)) {
return;
}
const datasetKey = key || "dmRelayBound";
if (element.dataset[datasetKey] === "true") {
return;
}
element.dataset[datasetKey] = "true";
element.addEventListener(eventName, handler);
};
bindOnce(
this.profileMessagesRelayAddButton,
"click",
() => {
void this.handleAddDmRelayPreference();
},
"dmRelayAddBound",
);
bindOnce(
this.profileMessagesRelayInput,
"keydown",
(event) => {
if (event.key === "Enter") {
event.preventDefault();
void this.handleAddDmRelayPreference();
}
},
"dmRelayInputBound",
);
bindOnce(
this.profileMessagesRelayPublishButton,
"click",
() => {
void this.handlePublishDmRelayPreferences();
},
"dmRelayPublishBound",
);
}
async refreshDmRelayPreferences({ force = false } = {}) {
const owner = this.resolveActiveDmRelayOwner();
if (!owner) {
@@ -4545,6 +4593,11 @@ export class ProfileModalController {
onToggleTypingIndicators: (enabled) => {
this.handleTypingIndicatorsToggle(enabled);
},
onOpenSettings: () => {
this.cacheDmRelayElements();
this.bindDmRelayControls();
this.populateDmRelayPreferences();
},
});
} catch (error) {
this.dmAppShell = null;
@@ -5428,26 +5481,7 @@ export class ProfileModalController {
});
}
if (this.profileMessagesRelayAddButton instanceof HTMLElement) {
this.profileMessagesRelayAddButton.addEventListener("click", () => {
void this.handleAddDmRelayPreference();
});
}
if (this.profileMessagesRelayInput instanceof HTMLElement) {
this.profileMessagesRelayInput.addEventListener("keydown", (event) => {
if (event.key === "Enter") {
event.preventDefault();
void this.handleAddDmRelayPreference();
}
});
}
if (this.profileMessagesRelayPublishButton instanceof HTMLElement) {
this.profileMessagesRelayPublishButton.addEventListener("click", () => {
void this.handlePublishDmRelayPreferences();
});
}
this.bindDmRelayControls();
if (this.profileMessageSendButton instanceof HTMLElement) {
this.profileMessageSendButton.addEventListener("click", () => {