Get rid of relay settings

This commit is contained in:
Jon Staab 2026-09-07 14:39:01 -07:00
parent 9c5b3d42d2
commit 39a4798546
9 changed files with 82 additions and 174 deletions

View file

@ -1,11 +1,16 @@
<script lang="ts">
import {onMount} from "svelte"
import {assoc} from "@welshman/lib"
import {publish} from "@welshman/app"
import Check from "@assets/icons/check.svg?dataurl"
import Bell from "@assets/icons/bell.svg?dataurl"
import BellOff from "@assets/icons/bell-off.svg?dataurl"
import Mailbox from "@assets/icons/mailbox.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import RelayList from "@app/components/RelayList.svelte"
import {messagingRelayLists, user} from "@app/core"
import {pushModal} from "@app/modal"
import {setChecked} from "@app/notifications"
import {notificationSettings} from "@app/settings"
@ -20,6 +25,16 @@
const toggleAlerts = () =>
notificationSettings.update(assoc("messages", !$notificationSettings.messages))
const showRelays = () =>
pushModal(RelayList, {
title: "DM Relays",
subtitle:
"Where you send and receive direct messages. Be sure to select relays that will accept your messages and messages from people you'd like to be in contact with.",
relays: $messagingRelayLists.urls($user.pubkey).$,
addRelay: (url: string) => $messagingRelayLists.addUrl(url).then(publish),
removeRelay: (url: string) => $messagingRelayLists.removeUrl(url).then(publish),
})
let ul: Element
onMount(() => {
@ -45,4 +60,10 @@
{/if}
</Button>
</li>
<li>
<Button onclick={showRelays}>
<Icon size={4} icon={Mailbox} />
DM relays
</Button>
</li>
</ul>

View file

@ -1,7 +1,6 @@
<script lang="ts">
import {Capacitor} from "@capacitor/core"
import ServerPath from "@assets/icons/server-path.svg?dataurl"
import RemoteControlMinimalistic from "@assets/icons/remote-controller-minimalistic.svg?dataurl"
import GalleryMinimalistic from "@assets/icons/gallery-minimalistic.svg?dataurl"
import Shield from "@assets/icons/shield-minimalistic.svg?dataurl"
import Bell from "@assets/icons/bell.svg?dataurl"
@ -42,13 +41,6 @@
Wallet
</Link>
{/if}
<Link
replaceState
href="/settings/relays"
class="aspect-square button button-neutral h-[unset] flex flex-col gap-2 text-center">
<Icon icon={RemoteControlMinimalistic} size={5} />
Relays
</Link>
<Link
replaceState
href="/settings/hosting"

View file

@ -2,7 +2,7 @@
import {onMount} from "svelte"
import {SvelteSet} from "svelte/reactivity"
import type {Readable} from "svelte/store"
import {tryCatch} from "@welshman/lib"
import {tryCatch, uniq} from "@welshman/lib"
import {isShareableRelayUrl, isIPAddress, normalizeRelayUrl} from "@welshman/util"
import type {Thunk} from "@welshman/app"
import {Relays} from "@welshman/app"
@ -18,7 +18,7 @@
import ModalFooter from "@lib/components/ModalFooter.svelte"
import RelayItem from "@app/components/RelayItem.svelte"
import {pushToast} from "@app/toast"
import {app, blockedRelayLists, user} from "@app/core"
import {app, blockedRelayLists, relayLists, user} from "@app/core"
interface Props {
relays: Readable<string[]>
@ -72,7 +72,15 @@
.slice(0, limit),
)
// Suggestions come from relay search, which only knows about relays whose NIP-11
// document has been fetched — so seed it from everyone's relay lists.
onMount(() => {
const urls = uniq($relayLists.all.get().flatMap(list => list.urls()))
for (const url of urls.filter(isShareableRelayUrl)) {
$app.use(Relays).load(url)
}
const scroller = createScroller({
element: element!,
delay: 300,

View file

@ -1,50 +0,0 @@
<script lang="ts">
import type {Readable} from "svelte/store"
import Check from "@assets/icons/check.svg?dataurl"
import DangerTriangle from "@assets/icons/danger-triangle.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import RelayList from "@app/components/RelayList.svelte"
import {pushModal} from "@app/modal"
interface Props {
icon: string
title: string
subtitle: string
relays: Readable<string[]>
addRelay: (url: string) => unknown
removeRelay: (url: string) => unknown
matchRelay?: (url: string) => boolean
}
const {icon, title, relays, subtitle, addRelay, removeRelay, matchRelay}: Props = $props()
const onclick = () =>
pushModal(RelayList, {title, subtitle, relays, addRelay, removeRelay, matchRelay})
</script>
<Button
class="font-normal flex h-[unset] w-full flex-nowrap py-4 text-left items-start justify-between"
{onclick}>
<div class="flex grow flex-row items-start gap-4">
<div class="flex h-7 w-7 shrink-0 items-center justify-center">
<Icon {icon} />
</div>
<div class="flex flex-col gap-1">
<p class="text-lg">
{title}
</p>
<p class="text-sm">
{subtitle}
</p>
</div>
</div>
<div class="flex items-center justify-end gap-1">
{#if $relays.length <= 1}
<Icon icon={DangerTriangle} />
{:else}
<Icon icon={Check} />
{/if}
{$relays.length}
</div>
</Button>

View file

@ -1,27 +1,47 @@
<script lang="ts">
import {MESSAGE} from "@welshman/util"
import type {TrustedEvent} from "@welshman/util"
import {publish} from "@welshman/app"
import Server from "@assets/icons/server.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import Badge from "@lib/components/Badge.svelte"
import Button from "@lib/components/Button.svelte"
import Modal from "@lib/components/Modal.svelte"
import ModalHeader from "@lib/components/ModalHeader.svelte"
import ModalTitle from "@lib/components/ModalTitle.svelte"
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
import RelayList from "@app/components/RelayList.svelte"
import RelayName from "@app/components/RelayName.svelte"
import SearchBody from "@app/components/SearchBody.svelte"
import {CONTENT_KINDS} from "@app/content"
import {app} from "@app/core"
import {app, relays, searchRelayLists, user} from "@app/core"
import {pushModal} from "@app/modal"
import {userSpaceUrls} from "@app/rooms"
const filter = {kinds: [MESSAGE, ...CONTENT_KINDS]}
const getSpaceUrl = (event: TrustedEvent) =>
$userSpaceUrls.find(url => $app.tracker.getRelays(event.id).has(url))
const showRelays = () =>
pushModal(RelayList, {
title: "Search Relays",
subtitle: "Relays that support searching for profiles and public notes.",
relays: $searchRelayLists.urls($user.pubkey).$,
addRelay: (url: string) => $searchRelayLists.addUrl(url).then(publish),
removeRelay: (url: string) => $searchRelayLists.removeUrl(url).then(publish),
matchRelay: (url: string) => Boolean($relays.get(url)?.hasNip(50)),
})
</script>
<Modal class="flex flex-col gap-2">
<ModalHeader>
<ModalTitle>Search</ModalTitle>
<ModalSubtitle>across all your spaces</ModalSubtitle>
<Button class="button button-link button-sm self-center" onclick={showRelays}>
<Icon size={4} icon={Server} />
Search relays
</Button>
</ModalHeader>
<SearchBody placeholder="Search your spaces..." relays={$userSpaceUrls} {filter}>
{#snippet badges(event)}

View file

@ -31,7 +31,6 @@ const staticTitles = new Map<string, string>([
["/settings/profile", "Profile Settings"],
["/settings/content", "Content Settings"],
["/settings/privacy", "Privacy Settings"],
["/settings/relays", "Relay Settings"],
["/settings/hosting", "Hosting"],
["/settings/alerts", "Alert Settings"],
["/settings/wallet", "Wallet Settings"],

View file

@ -4,7 +4,6 @@
import UserCircle from "@assets/icons/user-circle.svg?dataurl"
import Wallet from "@assets/icons/wallet.svg?dataurl"
import ServerPath from "@assets/icons/server-path.svg?dataurl"
import RemoteControlMinimalistic from "@assets/icons/remote-controller-minimalistic.svg?dataurl"
import Moon from "@assets/icons/moon.svg?dataurl"
import Code2 from "@assets/icons/code-2.svg?dataurl"
import Exit from "@assets/icons/logout-3.svg?dataurl"
@ -45,9 +44,6 @@
<Icon icon={Wallet} /> Wallet
</SecondaryNavItem>
{/if}
<SecondaryNavItem href="/settings/relays">
<Icon icon={RemoteControlMinimalistic} /> Relays
</SecondaryNavItem>
{#if HOSTING_ENABLED}
<SecondaryNavItem href="/settings/hosting">
<Icon icon={ServerPath} /> Hosting

View file

@ -1,5 +1,7 @@
<script lang="ts">
import {publish} from "@welshman/app"
import ShieldMinimalistic from "@assets/icons/shield-minimalistic.svg?dataurl"
import ForbiddenCircle from "@assets/icons/forbidden-circle.svg?dataurl"
import {preventDefault} from "@lib/html"
import FieldInline from "@lib/components/FieldInline.svelte"
import ToggleInput from "@lib/components/ToggleInput.svelte"
@ -8,6 +10,9 @@
import PageContent from "@lib/components/PageContent.svelte"
import Button from "@lib/components/Button.svelte"
import Spinner from "@lib/components/Spinner.svelte"
import RelayList from "@app/components/RelayList.svelte"
import {blockedRelayLists, user} from "@app/core"
import {pushModal} from "@app/modal"
import {pushToast} from "@app/toast"
import {PLATFORM_NAME} from "@app/env"
import {sendLogs} from "@app/logger"
@ -43,6 +48,15 @@
$settings.relay_auth = checked ? RelayAuthMode.Aggressive : RelayAuthMode.Conservative
}
const showBlockedRelays = () =>
pushModal(RelayList, {
title: "Blocked Relays",
subtitle: "These relays won't be used unless explicitly requested.",
relays: blockedRelayUrls,
addRelay: (url: string) => $blockedRelayLists.addUrl(url).then(publish),
removeRelay: (url: string) => $blockedRelayLists.removeUrl(url).then(publish),
})
const onsubmit = preventDefault(async () => {
loading = true
@ -56,6 +70,8 @@
})
const settings = createSettingsForm()
const blockedRelayUrls = $blockedRelayLists.urls($user.pubkey).$
let loading = $state(false)
let sendingLogs = $state(false)
</script>
@ -80,6 +96,20 @@
<p>Controls whether {PLATFORM_NAME} will identify you to relays not in your lists.</p>
{/snippet}
</FieldInline>
<FieldInline>
{#snippet label()}
<p>Blocked relays</p>
{/snippet}
{#snippet input()}
<Button class="button button-neutral" onclick={showBlockedRelays}>
<Icon icon={ForbiddenCircle} />
{$blockedRelayUrls.length} Blocked
</Button>
{/snippet}
{#snippet info()}
<p>These relays won't be used unless explicitly requested.</p>
{/snippet}
</FieldInline>
<FieldInline>
{#snippet label()}
<p>Report usage?</p>

View file

@ -1,108 +0,0 @@
<script lang="ts">
import {onMount} from "svelte"
import {uniq} from "@welshman/lib"
import {isShareableRelayUrl} from "@welshman/util"
import {publish} from "@welshman/app"
import Plane from "@assets/icons/plane.svg?dataurl"
import Inbox from "@assets/icons/inbox.svg?dataurl"
import Server from "@assets/icons/server.svg?dataurl"
import Mailbox from "@assets/icons/mailbox.svg?dataurl"
import Magnifier from "@assets/icons/magnifier.svg?dataurl"
import ForbiddenCircle from "@assets/icons/forbidden-circle.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import PageContent from "@lib/components/PageContent.svelte"
import RelaySettingsItem from "@app/components/RelaySettingsItem.svelte"
import RelaySettingsHealthChecks from "@app/components/RelaySettingsHealthChecks.svelte"
import {
blockedRelayLists,
messagingRelayLists,
relayLists,
relays,
searchRelayLists,
user,
} from "@app/core"
const readRelayUrls = $relayLists.readUrls($user.pubkey).$
const writeRelayUrls = $relayLists.writeUrls($user.pubkey).$
const searchRelayUrls = $searchRelayLists.urls($user.pubkey).$
const blockedRelayUrls = $blockedRelayLists.urls($user.pubkey).$
const messagingRelayUrls = $messagingRelayLists.urls($user.pubkey).$
const addReadRelay = (url: string) => $relayLists.addReadUrl(url).then(publish)
const removeReadRelay = (url: string) => $relayLists.removeReadUrl(url).then(publish)
const addWriteRelay = (url: string) => $relayLists.addWriteUrl(url).then(publish)
const removeWriteRelay = (url: string) => $relayLists.removeWriteUrl(url).then(publish)
const addMessagingRelay = (url: string) => $messagingRelayLists.addUrl(url).then(publish)
const removeMessagingRelay = (url: string) => $messagingRelayLists.removeUrl(url).then(publish)
const addSearchRelay = (url: string) => $searchRelayLists.addUrl(url).then(publish)
const removeSearchRelay = (url: string) => $searchRelayLists.removeUrl(url).then(publish)
const addBlockedRelay = (url: string) => $blockedRelayLists.addUrl(url).then(publish)
const removeBlockedRelay = (url: string) => $blockedRelayLists.removeUrl(url).then(publish)
const relaySupportsSearch = (url: string) => Boolean($relays.get(url)?.hasNip(50))
// Suggestions come from relay search, which only knows about relays whose NIP-11
// document has been fetched — so seed it from everyone's relay lists.
onMount(() => {
const urls = uniq($relayLists.all.get().flatMap(list => list.urls()))
for (const url of urls.filter(isShareableRelayUrl)) {
$relays.load(url)
}
})
</script>
<PageContent>
<RelaySettingsHealthChecks />
<div class="card flex flex-col gap-4 shadow-md">
<strong class="flex items-center gap-3 text-lg">
<Icon icon={Server} />
Your Relays
</strong>
<p class="mb-2">
Relays are servers which store your data, or allow you to find data from across the Nostr
network. We've set you up with some reasonable defaults, but if you're a power user, you can
customize your relay selections below.
</p>
<RelaySettingsItem
icon={Inbox}
title="Inbox Relays"
subtitle="Where other people should send notes intended for you. Be sure to select relays that will accept notes that tag you."
relays={readRelayUrls}
addRelay={addReadRelay}
removeRelay={removeReadRelay} />
<RelaySettingsItem
icon={Plane}
title="Outbox Relays"
subtitle="Where you send your public notes. Be sure to select relays that will accept your notes, and which will let people who follow you read them."
relays={writeRelayUrls}
addRelay={addWriteRelay}
removeRelay={removeWriteRelay} />
<RelaySettingsItem
icon={Mailbox}
title="DM Relays"
subtitle="Where you send and receive direct messages. Be sure to select relays that will accept your messages and messages from people you'd like to be in contact with."
relays={messagingRelayUrls}
addRelay={addMessagingRelay}
removeRelay={removeMessagingRelay} />
<RelaySettingsItem
icon={Magnifier}
title="Search Relays"
subtitle="Relays that support searching for profiles and public notes."
relays={searchRelayUrls}
addRelay={addSearchRelay}
removeRelay={removeSearchRelay}
matchRelay={relaySupportsSearch} />
<RelaySettingsItem
icon={ForbiddenCircle}
title="Blocked Relays"
subtitle="These relays won't be used unless explicitly requested."
relays={blockedRelayUrls}
addRelay={addBlockedRelay}
removeRelay={removeBlockedRelay} />
</div>
</PageContent>