Work on making relays mute-able

This commit is contained in:
Jonathan Staab 2023-04-06 16:22:14 -05:00
parent a166612601
commit 3b6f1f0fa6
15 changed files with 175 additions and 126 deletions

View File

@ -64,8 +64,8 @@
import PersonProfileInfo from "src/views/person/PersonProfileInfo.svelte"
import PersonShare from "src/views/person/PersonShare.svelte"
import AddRelay from "src/views/relays/AddRelay.svelte"
import RelayCard from "src/views/relays/RelayCard.svelte"
import GlobalRelays from "src/views/relays/GlobalRelays.svelte"
import RelayModal from "src/views/relays/RelayModal.svelte"
import MuteRelays from "src/views/relays/MuteRelays.svelte"
Object.assign(window, {cmd, user, keys, network, pool, sync, tables, bech32ToHex, hexToBech32})
@ -279,8 +279,10 @@
<NoteCreate pubkey={$modal.pubkey} nevent={$modal.nevent} />
{:else if $modal.type === "relay/add"}
<AddRelay />
{:else if $modal.type === "relays/global"}
<GlobalRelays />
{:else if $modal.type === "relays/mute"}
<MuteRelays />
{:else if $modal.type === "relays/modal"}
<RelayModal url={$modal.url} />
{:else if $modal.type === "onboarding"}
<Onboarding stage={$modal.stage} />
{:else if $modal.type === "room/edit"}

View File

@ -151,4 +151,4 @@ export const getThemeVariables = $theme =>
// Global relay setting
export const globalRelays = new WritableList([])
export const muteRelays = new WritableList([])

View File

@ -19,6 +19,8 @@
"py-2 px-4 rounded bg-input text-accent whitespace-nowrap border border-solid border-gray-6 hover:bg-input-hover",
"button-circle":
"w-10 h-10 flex justify-center items-center rounded-full bg-input text-accent whitespace-nowrap border border-solid border-gray-6 hover:bg-input-hover",
"button-circle-dark":
"w-10 h-10 flex justify-center items-center rounded-full bg-gray-8 text-white whitespace-nowrap border border-solid border-gray-7",
"button-accent":
"py-2 px-4 rounded bg-accent text-white whitespace-nowrap border border-solid border-accent-light hover:bg-accent-light",
})

View File

@ -13,10 +13,7 @@
let showModal = false
// Put previews last since we need to load them asynchronously
const annotated = sortBy(
({type}) => (type === "preview" ? 1 : 0),
links.filter(url => !url.startsWith("ws")).map(annotateMedia)
)
const annotated = sortBy(l => (l.type === "preview" ? 1 : 0), links.map(annotateMedia))
const close = () => {
onClose?.()

View File

@ -8,6 +8,7 @@
export let theme = "dark"
export let triggerType = "click"
export let placement = "top"
export let interactive = true
let trigger
let tooltip
@ -19,7 +20,7 @@
placement: placement as Placement,
appendTo: () => document.body,
allowHTML: true,
interactive: true,
interactive,
trigger: triggerType,
animation: "shift-away",
onShow: () => {

View File

@ -1,94 +1,37 @@
<script lang="ts">
import {find, propEq} from "ramda"
import {onMount} from "svelte"
import {poll, stringToHue, hsl} from "src/util/misc"
import {displayRelay} from "src/util/nostr"
import {between} from "hurdak/lib/hurdak"
import Content from "src/partials/Content.svelte"
import Anchor from "src/partials/Anchor.svelte"
import Feed from "src/views/feed/Feed.svelte"
import RelayTitle from "src/views/relays/RelayTitle.svelte"
import RelayJoin from "src/views/relays/RelayJoin.svelte"
import {relays} from "src/agent/tables"
import pool from "src/agent/pool"
import user from "src/agent/user"
import {muteRelays} from "src/app/ui"
export let url
const relay = relays.get(url) || {url}
let quality = null
let message = null
let showStatus = false
let joined = false
const {relays: userRelays} = user
$: joined = find(propEq("url", relay.url), $userRelays)
onMount(() => {
return poll(10_000, async () => {
;[quality, message] = pool.getQuality(relay.url)
})
})
document.title = displayRelay(relay)
</script>
<Content>
<div class="flex items-center justify-between gap-2">
<div class="flex items-center gap-2 text-xl">
<i class={relay.url.startsWith("wss") ? "fa fa-lock" : "fa fa-unlock"} />
<span class="border-b border-solid" style={`border-color: ${hsl(stringToHue(relay.url))}`}>
{displayRelay(relay)}
</span>
<span
on:mouseout={() => {
showStatus = false
}}
on:mouseover={() => {
showStatus = true
}}
class="h-2 w-2 cursor-pointer rounded-full bg-gray-6"
class:bg-gray-6={message === "Not connected"}
class:bg-danger={quality <= 0.3 && message !== "Not connected"}
class:bg-warning={between(0.3, 0.7, quality)}
class:bg-success={quality > 0.7} />
<p
class="hidden text-sm text-gray-1 transition-all sm:block"
class:opacity-0={!showStatus}
class:opacity-1={showStatus}>
{message}
</p>
</div>
<div class="flex flex-wrap items-center gap-3 whitespace-nowrap">
{#if relay.contact}
<Anchor type="button-circle" href={`mailto:${relay.contact}`}>
<i class="fa fa-envelope" />
</Anchor>
{/if}
{#if joined}
{#if $userRelays.length > 1}
<Anchor
type="button"
class="flex items-center gap-2 rounded-full"
on:click={() => user.removeRelay(relay.url)}>
<i class="fa fa-right-from-bracket" /> Leave
</Anchor>
{/if}
{:else}
<Anchor
type="button"
class="flex items-center gap-2 rounded-full"
on:click={() => user.addRelay(relay.url)}>
<i class="fa fa-right-to-bracket" /> Join
</Anchor>
{/if}
</div>
<RelayTitle {relay} />
<RelayJoin {relay} />
</div>
{#if relay.description}
<p>{relay.description}</p>
{/if}
</Content>
<div class="border-b border-solid border-gray-6" />
<Content>
<Feed relays={[relay]} filter={{kinds: [1]}} />
</Content>
{#if $muteRelays.includes(relay.url)}
<Content size="lg" class="text-center">
This relay has been muted.
<Anchor on:click={() => muteRelays.remove(relay.url)}>Unmute</Anchor>
</Content>
{:else}
<Content>
<Feed relays={[relay]} filter={{kinds: [1]}} />
</Content>
{/if}

View File

@ -1,6 +1,6 @@
<script lang="ts">
import {onMount} from "svelte"
import {objOf, partition, intersection, always, propEq, uniqBy, sortBy, prop} from "ramda"
import {find, partition, always, propEq, uniqBy, sortBy, prop} from "ramda"
import {fly} from "svelte/transition"
import {quantify} from "hurdak/lib/hurdak"
import {createScroller, now, timedelta, Cursor} from "src/util/misc"
@ -10,7 +10,7 @@
import Note from "src/views/notes/Note.svelte"
import user from "src/agent/user"
import network from "src/agent/network"
import {modal, globalRelays} from "src/app/ui"
import {modal, muteRelays} from "src/app/ui"
import {mergeParents} from "src/app"
export let filter
@ -89,7 +89,7 @@
onMount(() => {
const sub = network.listen({
relays,
relays: relays.filter(url => !$muteRelays.includes(url)),
filter: mergeFilter(filter, {since}),
onChunk,
})
@ -101,7 +101,7 @@
// Wait for this page to load before trying again
await network.load({
relays: $globalRelays.length > 0 ? $globalRelays.map(objOf("url")) : relays,
relays: relays.filter(url => !$muteRelays.includes(url)),
filter: mergeFilter(filter, cursor.getFilter()),
onChunk,
})
@ -133,7 +133,7 @@
<div class="flex flex-col gap-4">
{#each notes as note (note.id)}
{#if $globalRelays.length === 0 || intersection(note.seen_on, $globalRelays)}
{#if find(url => !$muteRelays.includes(url), note.seen_on)}
<Note depth={2} {note} />
{/if}
{/each}

View File

@ -1,30 +1,27 @@
<script lang="ts">
import {fly} from "svelte/transition"
import {quantify} from "hurdak/lib/hurdak"
import Anchor from "src/partials/Anchor.svelte"
import Popover from "src/partials/Popover.svelte"
import user from "src/agent/user"
import {modal, globalRelays} from "src/app/ui"
import {modal, muteRelays} from "src/app/ui"
export let pubkey = null
const {canPublish} = user
const openModal = () => {
modal.set({type: "relays/global"})
modal.set({type: "relays/mute"})
}
</script>
<div class="fixed bottom-0 right-0 z-10 m-8 flex flex-col items-center gap-3">
<div
transition:fly|local={{y: 20}}
class="transition-transform hover:scale-105 relative">
<Anchor type="button-circle" on:click={openModal}>
<div transition:fly|local={{y: 20}} class="relative transition-transform hover:scale-105">
<Anchor type="button-circle-dark" on:click={openModal}>
<i class="fa fa-filter mt-1" />
<span class="rounded-full absolute w-5 h-5 text-xs bottom-0 right-0 bg-gray-1
border border-solid border-gray-3 flex justify-center items-center
-mr-1">
{$globalRelays.length}
<span
class="absolute bottom-0 right-0 -mr-1 flex h-5 w-5 items-center
justify-center rounded-full border border-solid border-gray-7 bg-gray-8
text-xs">
{$muteRelays.length}
</span>
</Anchor>
</div>

View File

@ -464,17 +464,20 @@
</div>
<div on:click|stopPropagation class="flex items-center">
{#if pool.forceUrls.length === 0}
<div class="hidden group-hover:flex">
<div
class={cx("absolute top-0 right-0 m-3 sm:relative sm:m-0", {
"hidden group-hover:flex": !showEntire,
flex: showEntire,
})}>
{#each note.seen_on as url}
<Popover triggerType="mouseenter">
<div slot="trigger" class="p-1">
<Popover triggerType="mouseenter" interactive={false}>
<div slot="trigger" class="cursor-pointer p-1">
<div
class="h-3 w-3 rounded-full border border-solid border-gray-6"
style={`background: ${hsl(stringToHue(url))}`} />
</div>
<div slot="tooltip">
{displayRelay({url})}
style={`background: ${hsl(stringToHue(url))}`}
on:click={() => modal.set({type: "relays/modal", url})} />
</div>
<div slot="tooltip">{displayRelay({url})}</div>
</Popover>
{/each}
</div>
@ -628,9 +631,11 @@
{/if}
<h1 class="staatliches text-2xl">Relays</h1>
<p>This note was found on the {quantify(note.seen_on.length, "relay")} below.</p>
{#each note.seen_on as url}
<RelayCard theme="black" showControls relay={{url}} />
{/each}
<div class="flex flex-col gap-2">
{#each note.seen_on as url}
<RelayCard theme="black" relay={{url}} />
{/each}
</div>
<h1 class="staatliches text-2xl">Details</h1>
<CopyValue label="Identifier" value={nevent} />
<CopyValue label="Event ID (note)" value={bech32Note} />

View File

@ -32,7 +32,10 @@
const {type, value} = content[i]
// Find links on their own line and remove them from content
if (type === "link" || ["nostr:note", "nostr:nevent"].includes(type)) {
if (
(type === "link" && !value.startsWith("ws")) ||
["nostr:note", "nostr:nevent"].includes(type)
) {
const prev = content[i - 1]
const next = content[i + 1]

View File

@ -1,18 +1,17 @@
<script>
import {without, pluck} from 'ramda'
import {sortBy, identity, uniq, pluck} from 'ramda'
import {fly} from "svelte/transition"
import Toggle from "src/partials/Toggle.svelte"
import Content from "src/partials/Content.svelte"
import RelayCard from "src/partials/RelayCard.svelte"
import user from "src/agent/user"
import {globalRelays} from "src/app/ui"
import {muteRelays} from "src/app/ui"
const {relays} = user
const isSelected = url => $globalRelays.length === 0 || $globalRelays.includes(url)
const toggle = url =>
$globalRelays.length === 0
? globalRelays.set(without([url], pluck('url', $relays)))
: globalRelays.toggle(url)
const isMuted = url => $muteRelays.includes(url)
const toggle = url => muteRelays.toggle(url)
$: allUrls = sortBy(identity, uniq($muteRelays.concat(pluck('url', $relays))))
</script>
<div in:fly={{y: 20}}>
@ -20,29 +19,29 @@
<div class="flex justify-between">
<div class="flex items-center gap-2">
<i class="fa fa-server fa-lg" />
<h2 class="staatliches text-2xl">Explore relays</h2>
<h2 class="staatliches text-2xl">Mute relays</h2>
</div>
</div>
<div class="flex items-center gap-2 text-gray-4">
<i class="fa fa-warning" /> Advanced Feature
</div>
<p>
Select which of your relays to use to request feeds. This is separate from your main
relay selections, and is just to help you explore what different relays have to offer.
Some notes from other relays will be included if required for context.
Select relays to temporarily mute. This is separate from your main relay selections,
and is just to help you explore what different relays have to offer.
Muted relays may sometimes still be used to load context for other notes.
</p>
{#if $relays.length === 0}
{#if allUrls.length === 0}
<div class="mt-8 flex items-center justify-center gap-2 text-center">
<i class="fa fa-triangle-exclamation" />
No relays connected
</div>
{/if}
<div class="grid grid-cols-1 gap-4">
{#each $relays as relay (relay.url)}
<RelayCard {relay}>
{#each allUrls as url}
<RelayCard relay={{url}}>
<div slot="controls" class="flex justify-between gap-2">
<span>Include in feeds?</span>
<Toggle value={isSelected(relay.url)} on:change={() => toggle(relay.url)} />
<span>Mute this relay?</span>
<Toggle value={isMuted(url)} on:change={() => toggle(url)} />
</div>
</RelayCard>
{/each}

View File

@ -0,0 +1,36 @@
<script lang="ts">
import {find, propEq} from "ramda"
import Anchor from 'src/partials/Anchor.svelte'
import user from "src/agent/user"
export let relay
const {relays: userRelays} = user
$: joined = find(propEq("url", relay.url), $userRelays)
</script>
<div class="flex flex-wrap items-center gap-3 whitespace-nowrap">
{#if relay.contact}
<Anchor type="button-circle" href={`mailto:${relay.contact}`}>
<i class="fa fa-envelope" />
</Anchor>
{/if}
{#if joined}
{#if $userRelays.length > 1}
<Anchor
type="button"
class="flex items-center gap-2 rounded-full"
on:click={() => user.removeRelay(relay.url)}>
<i class="fa fa-right-from-bracket" /> Leave
</Anchor>
{/if}
{:else}
<Anchor
type="button"
class="flex items-center gap-2 rounded-full"
on:click={() => user.addRelay(relay.url)}>
<i class="fa fa-right-to-bracket" /> Join
</Anchor>
{/if}
</div>

View File

@ -0,0 +1,20 @@
<script lang="ts">
import Content from "src/partials/Content.svelte"
import RelayTitle from "src/views/relays/RelayTitle.svelte"
import RelayJoin from "src/views/relays/RelayJoin.svelte"
import {relays} from "src/agent/tables"
export let url
const relay = relays.get(url) || {url}
</script>
<Content>
<div class="flex items-center justify-between gap-2">
<RelayTitle {relay} />
<RelayJoin {relay} />
</div>
{#if relay.description}
<p>{relay.description}</p>
{/if}
</Content>

View File

@ -0,0 +1,44 @@
<script lang="ts">
import {onMount} from "svelte"
import {between} from "hurdak/lib/hurdak"
import {displayRelay} from "src/util/nostr"
import {poll, stringToHue, hsl} from "src/util/misc"
import pool from 'src/agent/pool'
export let relay
let quality = null
let message = null
let showStatus = false
onMount(() => {
return poll(10_000, async () => {
;[quality, message] = pool.getQuality(relay.url)
})
})
</script>
<div class="flex items-center gap-2 text-xl">
<i class={relay.url.startsWith("wss") ? "fa fa-lock" : "fa fa-unlock"} />
<span class="border-b border-solid" style={`border-color: ${hsl(stringToHue(relay.url))}`}>
{displayRelay(relay)}
</span>
<span
on:mouseout={() => {
showStatus = false
}}
on:mouseover={() => {
showStatus = true
}}
class="h-2 w-2 cursor-pointer rounded-full bg-gray-6"
class:bg-gray-6={message === "Not connected"}
class:bg-danger={quality <= 0.3 && message !== "Not connected"}
class:bg-warning={between(0.3, 0.7, quality)}
class:bg-success={quality > 0.7} />
<p
class="hidden text-sm text-gray-1 transition-all sm:block"
class:opacity-0={!showStatus}
class:opacity-1={showStatus}>
{message}
</p>
</div>