Rough out chat

This commit is contained in:
Jon Staab
2024-10-08 11:39:16 -07:00
parent 7ffd02b736
commit 8698dcc359
59 changed files with 833 additions and 437 deletions
+3 -1
View File
@@ -107,7 +107,9 @@
<div data-theme={$theme}>
<div class="flex h-screen overflow-hidden">
<PrimaryNav />
<slot />
{#key $page.params}
<slot />
{/key}
</div>
<dialog bind:this={dialog} class="modal modal-bottom !z-modal sm:modal-middle">
{#if prev && !prev.options?.drawer}
+1 -1
View File
@@ -17,7 +17,7 @@
onMount(() => {
const sub = discoverRelays()
const scroller = createScroller({
element: element.closest('.max-h-screen')!,
element: element.closest(".max-h-screen")!,
onScroll: () => {
limit += 20
},
+2 -3
View File
@@ -19,10 +19,9 @@
</label>
<div class="grid grid-cols-2 gap-4 md:grid-cols-2">
{#each searchThemes.searchValues(term) as name}
<div class="card2 bg-alt shadow-xl flex flex-col justify-center gap-4" data-theme={name}>
<div class="card2 bg-alt flex flex-col justify-center gap-4 shadow-xl" data-theme={name}>
<h2 class="card2 bg-alt text-center capitalize">{name}</h2>
<button class="btn btn-primary w-full" on:click={() => theme.set(name)}
>Use Theme</button>
<button class="btn btn-primary w-full" on:click={() => theme.set(name)}>Use Theme</button>
</div>
{/each}
</div>
+18 -14
View File
@@ -1,8 +1,8 @@
<script lang="ts">
import {onMount} from 'svelte'
import {ellipsize, ctx, ago, remove} from '@welshman/lib'
import {WRAP} from '@welshman/util'
import {pubkey, subscribe} from '@welshman/app'
import {onMount} from "svelte"
import {ctx, ago, remove} from "@welshman/lib"
import {WRAP} from "@welshman/util"
import {pubkey, subscribe} from "@welshman/app"
import {fly} from "@lib/transition"
import Icon from "@lib/components/Icon.svelte"
import Page from "@lib/components/Page.svelte"
@@ -16,8 +16,8 @@
import ProfileCircle from "@app/components/ProfileCircle.svelte"
import ProfileCircles from "@app/components/ProfileCircles.svelte"
import ChatStart from "@app/components/ChatStart.svelte"
import {chatSearch, pullConservatively} from '@app/state'
import {pushModal} from '@app/modal'
import {chatSearch, pullConservatively} from "@app/state"
import {pushModal} from "@app/modal"
const startChat = () => pushModal(ChatStart)
@@ -26,7 +26,7 @@
$: chats = $chatSearch.searchOptions(term).filter(c => c.pubkeys.length > 1)
onMount(() => {
const filter = {kinds: [WRAP], '#p': [$pubkey!]}
const filter = {kinds: [WRAP], "#p": [$pubkey!]}
const sub = subscribe({filters: [{...filter, since: ago(30)}]})
pullConservatively({
@@ -64,29 +64,33 @@
</SecondaryNavHeader>
</div>
</SecondaryNavSection>
<label class="input input-bordered input-sm flex items-center gap-2 mx-6 -mt-4" in:fly={{delay: 200}}>
<label
class="input input-sm input-bordered mx-6 -mt-4 flex items-center gap-2"
in:fly={{delay: 200}}>
<Icon icon="magnifer" />
<input bind:value={term} class="grow" type="text" />
</label>
<div class="overflow-auto">
{#each chats as {id, pubkeys, messages}, i (id)}
{#each chats as { id, pubkeys, messages }, i (id)}
{@const message = messages[0]}
{@const others = remove($pubkey, pubkeys)}
<div class="px-6 py-2 border-t border-base-100 border-solid hover:bg-base-100 transition-colors cursor-pointer">
<div
class="cursor-pointer border-t border-solid border-base-100 px-6 py-2 transition-colors hover:bg-base-100">
<Link class="flex flex-col justify-start gap-1" href="/home/{id}">
<div class="flex gap-2 items-center">
<div class="flex items-center gap-2">
{#if others.length === 1}
<ProfileCircle pubkey={others[0]} size={5} />
<Name pubkey={others[0]} />
{:else}
<ProfileCircles pubkeys={others} size={5} />
<p class="whitespace-nowrap overflow-hidden text-ellipsis">
<p class="overflow-hidden text-ellipsis whitespace-nowrap">
<Name pubkey={others[0]} />
and {others.length - 1} {others.length > 2 ? 'others' : 'other'}
and {others.length - 1}
{others.length > 2 ? "others" : "other"}
</p>
{/if}
</div>
<p class="text-sm whitespace-nowrap overflow-hidden text-ellipsis">
<p class="overflow-hidden text-ellipsis whitespace-nowrap text-sm">
{message.content}
</p>
</Link>
+3 -2
View File
@@ -8,9 +8,10 @@
const browseSpaces = () => goto("/discover")
const leaveFeedback = () => goto("/home/97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322")
const leaveFeedback = () =>
goto("/home/97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322")
const donate = () => window.open('https://geyser.fund/project/flotilla')
const donate = () => window.open("https://geyser.fund/project/flotilla")
</script>
<div class="hero min-h-screen bg-base-200">
+136
View File
@@ -0,0 +1,136 @@
<script lang="ts" context="module">
type Element = {
id: string
type: "date" | "note"
value: string | TrustedEvent
showPubkey: boolean
}
</script>
<script lang="ts">
import {page} from "$app/stores"
import {ctx, uniq, sortBy, remove} from "@welshman/lib"
import type {TrustedEvent, EventContent} from "@welshman/util"
import {createEvent, DIRECT_MESSAGE} from "@welshman/util"
import {Nip59} from "@welshman/signer"
import {
pubkey,
signer,
formatTimestampAsDate,
tagPubkey,
makeThunk,
publishThunk,
} from "@welshman/app"
import {fly} from "@lib/transition"
import Spinner from "@lib/components/Spinner.svelte"
import Divider from "@lib/components/Divider.svelte"
import Name from "@app/components/Name.svelte"
import ProfileCircle from "@app/components/ProfileCircle.svelte"
import ProfileCircles from "@app/components/ProfileCircles.svelte"
import ChatMessage from "@app/components/ChatMessage.svelte"
import ChatCompose from "@app/components/ChannelCompose.svelte"
import {deriveChat, splitChatId} from "@app/state"
const {chat: id} = $page.params
const chat = deriveChat(id)
const pubkeys = splitChatId(id)
const others = remove($pubkey, pubkeys)
const assertEvent = (e: any) => e as TrustedEvent
const onSubmit = async ({content, ...params}: EventContent) => {
const tags = [...params.tags, ...pubkeys.map(pubkey => tagPubkey(pubkey))]
const template = createEvent(DIRECT_MESSAGE, {content, tags})
const nip59 = Nip59.fromSigner($signer!)
for (const recipient of uniq(pubkeys)) {
const rumor = await nip59.wrap(recipient, template)
publishThunk(
makeThunk({
event: rumor.wrap,
relays: ctx.app.router.PublishMessage(recipient).getUrls(),
}),
)
}
}
let loading = true
let elements: Element[] = []
$: {
elements = []
let previousDate
let previousPubkey
for (const event of sortBy(e => e.created_at, $chat?.messages || [])) {
const {id, pubkey, created_at} = event
const date = formatTimestampAsDate(created_at)
if (date !== previousDate) {
elements.push({type: "date", value: date, id: date, showPubkey: false})
}
elements.push({
id,
type: "note",
value: event,
showPubkey: date !== previousDate || previousPubkey !== pubkey,
})
previousDate = date
previousPubkey = pubkey
}
elements.reverse()
}
setTimeout(() => {
loading = false
}, 3000)
</script>
<div class="relative flex h-screen flex-col">
<div class="relative z-feature mx-2 rounded-xl pt-4">
<div
class="flex min-h-12 items-center justify-between gap-4 rounded-xl bg-base-100 px-4 shadow-xl">
<div class="flex items-center gap-2">
{#if others.length === 1}
<ProfileCircle pubkey={others[0]} size={5} />
<Name pubkey={others[0]} />
{:else}
<ProfileCircles pubkeys={others} size={5} />
<p class="overflow-hidden text-ellipsis whitespace-nowrap">
<Name pubkey={others[0]} />
and {others.length - 1}
{others.length > 2 ? "others" : "other"}
</p>
{/if}
</div>
</div>
</div>
<div class="-mt-2 flex flex-grow flex-col-reverse overflow-auto py-2">
{#each elements as { type, id, value, showPubkey } (id)}
{#if type === "date"}
<Divider>{value}</Divider>
{:else}
<div in:fly>
<ChatMessage event={assertEvent(value)} {pubkeys} {showPubkey} />
</div>
{/if}
{/each}
<p class="flex h-10 items-center justify-center py-20">
<Spinner {loading}>
{#if loading}
Looking for messages...
{:else}
End of message history
{/if}
</Spinner>
</p>
</div>
<div class="shadow-top-xl border-t border-solid border-base-100 bg-base-100">
<ChatCompose {onSubmit} />
</div>
</div>
+31 -33
View File
@@ -1,48 +1,47 @@
<script lang="ts">
import {onMount} from 'svelte'
import {derived} from 'svelte/store'
import {createScroller} from '@lib/html'
import {shuffle, sortBy, sleep, ago, DAY, HOUR, pushToMapKey} from '@welshman/lib'
import {getListValues, getAncestorTagValues, NOTE, REACTION} from '@welshman/util'
import type {TrustedEvent} from '@welshman/util'
import {deriveEvents} from '@welshman/store'
import {profileSearch, repository, userFollows, load} from '@welshman/app'
import Spinner from '@lib/components/Spinner.svelte'
import NoteCard from '@app/components/NoteCard.svelte'
import Content from '@app/components/Content.svelte'
import {onMount} from "svelte"
import {derived} from "svelte/store"
import {createScroller} from "@lib/html"
import {sortBy, sleep, ago, DAY, HOUR, pushToMapKey} from "@welshman/lib"
import {
getListTags,
getPubkeyTagValues,
getAncestorTagValues,
NOTE,
REACTION,
} from "@welshman/util"
import type {TrustedEvent} from "@welshman/util"
import {deriveEvents} from "@welshman/store"
import {repository, userFollows, load} from "@welshman/app"
import Spinner from "@lib/components/Spinner.svelte"
import NoteCard from "@app/components/NoteCard.svelte"
import Content from "@app/components/Content.svelte"
let element: Element
let loading = sleep(3000)
let events: TrustedEvent[] = []
const since = ago(DAY)
const authors = getListValues("p", $userFollows)
const loading = sleep(3000)
const authors = getPubkeyTagValues(getListTags($userFollows))
const notesFilter = {kinds: [NOTE], authors, since}
const notes = deriveEvents(repository, {filters: [notesFilter]})
const reactionsFilter = {kinds: [REACTION], '#p': authors, since}
const reactionsFilter = {kinds: [REACTION], "#p": authors, since}
const reactions = deriveEvents(repository, {filters: [reactionsFilter]})
const reactionsByParent = derived(
reactions,
$reactions => {
const $reactionsByParent = new Map<string, TrustedEvent[]>()
const reactionsByParent = derived(reactions, $reactions => {
const $reactionsByParent = new Map<string, TrustedEvent[]>()
for (const event of $reactions) {
const [parentId] = getAncestorTagValues(event.tags).replies
for (const event of $reactions) {
const [parentId] = getAncestorTagValues(event.tags).replies
if (parentId) {
pushToMapKey($reactionsByParent, parentId, event)
}
if (parentId) {
pushToMapKey($reactionsByParent, parentId, event)
}
return $reactionsByParent
}
)
const isLike = (e: TrustedEvent) =>
e.kind === REACTION && ["+", ""].includes(e.content)
return $reactionsByParent
})
const isReplyOf = (e: TrustedEvent, p: TrustedEvent) =>
getAncestorTagValues(e.tags).replies.includes(e.id)
const isLike = (e: TrustedEvent) => e.kind === REACTION && ["+", ""].includes(e.content)
const scoreEvent = (e: TrustedEvent) => {
const thisReactions = $reactionsByParent.get(e.id) || []
@@ -57,12 +56,12 @@
load({filters: [notesFilter, reactionsFilter]})
const scroller = createScroller({
element: element.closest('.max-h-screen')!,
element: element.closest(".max-h-screen")!,
onScroll: () => {
const seen = new Set(events.map(e => e.id))
const eligible = sortBy(
scoreEvent,
$notes.filter(e => !seen.has(e.id) && getAncestorTagValues(e.tags).replies.length === 0)
$notes.filter(e => !seen.has(e.id) && getAncestorTagValues(e.tags).replies.length === 0),
)
events = [...events, ...eligible.slice(0, 10)]
@@ -73,7 +72,6 @@
})
</script>
<div class="content column gap-4" bind:this={element}>
{#await loading}
<div class="center my-20">
+10 -13
View File
@@ -1,25 +1,23 @@
<script lang="ts">
import {onMount} from 'svelte'
import {createScroller} from '@lib/html'
import Icon from '@lib/components/Icon.svelte'
import {shuffle} from '@welshman/lib'
import {getListValues} from '@welshman/util'
import {profileSearch, userFollows} from '@welshman/app'
import PeopleItem from '@app/components/PeopleItem.svelte'
import {onMount} from "svelte"
import {createScroller} from "@lib/html"
import Icon from "@lib/components/Icon.svelte"
import {shuffle} from "@welshman/lib"
import {getPubkeyTagValues, getListTags} from "@welshman/util"
import {profileSearch, userFollows} from "@welshman/app"
import PeopleItem from "@app/components/PeopleItem.svelte"
const defaultPubkeys = shuffle(getListValues("p", $userFollows))
const defaultPubkeys = shuffle(getPubkeyTagValues(getListTags($userFollows)))
let term = ""
let limit = 10
let element: Element
$: pubkeys = term
? $profileSearch.searchValues(term)
: defaultPubkeys
$: pubkeys = term ? $profileSearch.searchValues(term) : defaultPubkeys
onMount(() => {
const scroller = createScroller({
element: element.closest('.max-h-screen')!,
element: element.closest(".max-h-screen")!,
onScroll: () => {
limit += 10
},
@@ -29,7 +27,6 @@
})
</script>
<div class="content column gap-4" bind:this={element}>
<h1 class="superheading mt-20">People</h1>
<p class="text-center">Get the latest from people in your network</p>
+13 -26
View File
@@ -1,26 +1,17 @@
<script lang="ts">
import {nip19} from 'nostr-tools'
import type {SvelteComponent} from 'svelte'
import tippy, {type Instance} from "tippy.js"
import {append, always, remove, uniq} from '@welshman/lib'
import {getListValues, MUTES} from '@welshman/util'
import {userMutes, profileSearch, tagPubkey} from '@welshman/app'
import Icon from '@lib/components/Icon.svelte'
import Field from '@lib/components/Field.svelte'
import Tippy from '@lib/components/Tippy.svelte'
import Link from '@lib/components/Link.svelte'
import Button from '@lib/components/Button.svelte'
import Suggestions from '@lib/editor/Suggestions.svelte'
import SuggestionProfile from '@lib/editor/SuggestionProfile.svelte'
import ProfileMultiSelect from '@app/components/ProfileMultiSelect.svelte'
import {entityLink} from '@app/state'
import {updateList} from '@app/commands'
import {pushToast} from '@app/toast'
import {always} from "@welshman/lib"
import {getListTags, getPubkeyTagValues, MUTES} from "@welshman/util"
import {userMutes, tagPubkey} from "@welshman/app"
import Field from "@lib/components/Field.svelte"
import Button from "@lib/components/Button.svelte"
import ProfileMultiSelect from "@app/components/ProfileMultiSelect.svelte"
import {updateList} from "@app/commands"
import {pushToast} from "@app/toast"
let mutedPubkeys = getListValues("p", $userMutes)
let mutedPubkeys = getPubkeyTagValues(getListTags($userMutes))
const reset = () => {
mutedPubkeys = getListValues("p", $userMutes)
mutedPubkeys = getPubkeyTagValues(getListTags($userMutes))
}
const onSubmit = async () => {
@@ -38,13 +29,9 @@
<ProfileMultiSelect bind:value={mutedPubkeys} />
</div>
</Field>
<div class="flex flex-row items-center justify-between gap-4 mt-4">
<Button class="btn btn-neutral" on:click={reset}>
Discard Changes
</Button>
<Button type="submit" class="btn btn-primary">
Save Changes
</Button>
<div class="mt-4 flex flex-row items-center justify-between gap-4">
<Button class="btn btn-neutral" on:click={reset}>Discard Changes</Button>
<Button type="submit" class="btn btn-primary">Save Changes</Button>
</div>
</div>
</form>
+4 -2
View File
@@ -2,7 +2,7 @@
import Link from "@lib/components/Link.svelte"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import {entityLink} from '@app/state'
import {entityLink} from "@app/state"
const nprofile =
"nprofile1qqsf03c2gsmx5ef4c9zmxvlew04gdh7u94afnknp33qvv3c94kvwxgspz4mhxue69uhhyetvv9ujuerpd46hxtnfduhsz9rhwden5te0wfjkcctev93xcefwdaexwtcpzdmhxue69uhhqatjwpkx2urpvuhx2ue0vamm57"
@@ -22,7 +22,9 @@
<div class="card2 bg-alt flex flex-col gap-2 text-center shadow-2xl">
<h3 class="text-2xl sm:h-12">Get in touch</h3>
<p class="sm:h-16">Having problems? Let us know by filing an issue.</p>
<Link class="btn btn-primary" href="/home/97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322">
<Link
class="btn btn-primary"
href="/home/97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322">
Open an Issue
</Link>
</div>
+33 -27
View File
@@ -1,26 +1,31 @@
<script lang="ts">
import {nip19} from 'nostr-tools'
import {last, ctx} from "@welshman/lib"
import {PROFILE, createEvent, displayPubkey, displayProfile, makeProfile, editProfile, createProfile, isPublishedProfile} from "@welshman/util"
import {pubkey, getProfile, displayHandle, makeThunk, publishThunk} from "@welshman/app"
import {slide} from '@lib/transition'
import {
createEvent,
displayPubkey,
displayProfile,
makeProfile,
editProfile,
createProfile,
isPublishedProfile,
} from "@welshman/util"
import {pubkey, profilesByPubkey, makeThunk, publishThunk} from "@welshman/app"
import {slide} from "@lib/transition"
import Icon from "@lib/components/Icon.svelte"
import Field from '@lib/components/Field.svelte'
import Field from "@lib/components/Field.svelte"
import Button from "@lib/components/Button.svelte"
import Avatar from "@lib/components/Avatar.svelte"
import InputProfilePicture from "@lib/components/InputProfilePicture.svelte"
import Content from '@app/components/Content.svelte'
import InfoHandle from '@app/components/InfoHandle.svelte'
import Content from "@app/components/Content.svelte"
import InfoHandle from "@app/components/InfoHandle.svelte"
import {pushModal} from "@app/modal"
import {pushToast} from "@app/toast"
const npub = nip19.npubEncode($pubkey!)
const pubkeyDisplay = displayPubkey($pubkey!)
const displayNip05 = (nip05: string) =>
nip05?.startsWith("_@") ? last(nip05.split("@")) : nip05
const displayNip05 = (nip05: string) => (nip05?.startsWith("_@") ? last(nip05.split("@")) : nip05)
const cloneProfile = () => ({...(getProfile($pubkey!) || makeProfile())})
const cloneProfile = () => ({...($profilesByPubkey.get($pubkey!) || makeProfile())})
const toggleEdit = () => {
editing = !editing
@@ -52,23 +57,23 @@
<div class="content column gap-4">
<div class="card2 bg-alt shadow-xl">
<div class="flex gap-2 justify-between">
<div class="flex gap-3 max-w-full">
<div class="flex justify-between gap-2">
<div class="flex max-w-full gap-3">
<div class="py-1">
<Avatar src={profile?.picture} size={10} />
</div>
<div class="flex flex-col min-w-0">
<div class="flex gap-2 items-center">
<div class="text-bold text-ellipsis overflow-hidden">
<div class="flex min-w-0 flex-col">
<div class="flex items-center gap-2">
<div class="text-bold overflow-hidden text-ellipsis">
{displayProfile(profile, pubkeyDisplay)}
</div>
</div>
<div class="text-sm opacity-75 text-ellipsis overflow-hidden">
<div class="overflow-hidden text-ellipsis text-sm opacity-75">
{profile?.nip05 ? displayNip05(profile.nip05) : pubkeyDisplay}
</div>
</div>
</div>
<Button class="btn btn-neutral btn-circle w-12 h-12 center -mt-4 -mr-4" on:click={toggleEdit}>
<Button class="center btn btn-circle btn-neutral -mr-4 -mt-4 h-12 w-12" on:click={toggleEdit}>
<Icon icon="pen-new-square" />
</Button>
</div>
@@ -90,7 +95,11 @@
</Field>
<Field>
<p slot="label">About You</p>
<textarea class="textarea textarea-bordered leading-4" rows="3" bind:value={profile.about} slot="input" />
<textarea
class="textarea textarea-bordered leading-4"
rows="3"
bind:value={profile.about}
slot="input" />
</Field>
<Field>
<p slot="label">Nostr Address</p>
@@ -99,16 +108,13 @@
<input bind:value={profile.nip05} class="grow" type="text" />
</label>
<p slot="info">
<Button class="link" on:click={() => pushModal(InfoHandle)}>What is a nostr address?</Button>
<Button class="link" on:click={() => pushModal(InfoHandle)}
>What is a nostr address?</Button>
</p>
</Field>
<div class="flex flex-row items-center justify-between gap-4 mt-4">
<Button class="btn btn-neutral" on:click={stopEdit}>
Discard Changes
</Button>
<Button type="submit" class="btn btn-primary">
Save Changes
</Button>
<div class="mt-4 flex flex-row items-center justify-between gap-4">
<Button class="btn btn-neutral" on:click={stopEdit}>Discard Changes</Button>
<Button type="submit" class="btn btn-primary">Save Changes</Button>
</div>
</form>
{/if}
+23 -19
View File
@@ -1,14 +1,19 @@
<script lang="ts">
import {derived} from "svelte/store"
import type {Readable} from 'svelte/store'
import {relaySearch, getRelayUrls, userRelaySelections, userInboxRelaySelections, getReadRelayUrls, getWriteRelayUrls} from "@welshman/app"
import {
getRelayUrls,
userRelaySelections,
userInboxRelaySelections,
getReadRelayUrls,
getWriteRelayUrls,
} from "@welshman/app"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import Collapse from "@lib/components/Collapse.svelte"
import RelayItem from "@app/components/RelayItem.svelte"
import RelayAdd from "@app/components/RelayAdd.svelte"
import {pushModal} from '@app/modal'
import {setRelayPolicy, setInboxRelayPolicy} from '@app/commands'
import {pushModal} from "@app/modal"
import {setRelayPolicy, setInboxRelayPolicy} from "@app/commands"
const readRelayUrls = derived(userRelaySelections, getReadRelayUrls)
const writeRelayUrls = derived(userRelaySelections, getWriteRelayUrls)
@@ -41,20 +46,20 @@
<div class="content column gap-4">
<Collapse class="card2 bg-alt column gap-4">
<h2 slot="title" class="text-xl flex items-center gap-3">
<h2 slot="title" class="flex items-center gap-3 text-xl">
<Icon icon="earth" />
Broadcast Relays
</h2>
<p slot="description" class="text-sm">
These relays will be advertised on your profile as places 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.
These relays will be advertised on your profile as places 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.
</p>
<div class="column gap-2">
{#each $writeRelayUrls.sort() as url (url)}
<RelayItem {url}>
<Button
class="flex items-center tooltip"
class="tooltip flex items-center"
data-tip="Stop using this relay"
on:click={() => removeWriteRelay(url)}>
<Icon icon="close-circle" />
@@ -70,20 +75,19 @@
</div>
</Collapse>
<Collapse class="card2 bg-alt column gap-4">
<h2 slot="title" class="text-xl flex items-center gap-3">
<h2 slot="title" class="flex items-center gap-3 text-xl">
<Icon icon="inbox" />
Inbox Relays
</h2>
<p slot="description" class="text-sm">
These relays will be advertised on your profile as places where other people should
send notes intended for you. Be sure to select relays that will accept notes that
tag you.
These relays will be advertised on your profile as places where other people should send notes
intended for you. Be sure to select relays that will accept notes that tag you.
</p>
<div class="column gap-2">
{#each $readRelayUrls.sort() as url (url)}
<RelayItem {url}>
<Button
class="flex items-center tooltip"
class="tooltip flex items-center"
data-tip="Stop using this relay"
on:click={() => removeReadRelay(url)}>
<Icon icon="close-circle" />
@@ -99,20 +103,20 @@
</div>
</Collapse>
<Collapse class="card2 bg-alt column gap-4">
<h2 slot="title" class="text-xl flex items-center gap-3">
<h2 slot="title" class="flex items-center gap-3 text-xl">
<Icon icon="mailbox" />
Messaging Relays
</h2>
<p slot="description" class="text-sm">
These relays will be advertised on your profile as places you use to 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.
These relays will be advertised on your profile as places you use to 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.
</p>
<div class="column gap-2">
{#each $inboxRelayUrls.sort() as url (url)}
<RelayItem {url}>
<Button
class="flex items-center tooltip"
class="tooltip flex items-center"
data-tip="Stop using this relay"
on:click={() => removeInboxRelay(url)}>
<Icon icon="close-circle" />
+1 -1
View File
@@ -1,7 +1,7 @@
<script lang="ts">
import {onMount} from "svelte"
import {page} from "$app/stores"
import {sort, now} from "@welshman/lib"
import {sort} from "@welshman/lib"
import {displayRelayUrl, REACTION, NOTE, EVENT_DATE, EVENT_TIME, CLASSIFIED} from "@welshman/util"
import {subscribe} from "@welshman/app"
import {fly, slide} from "@lib/transition"
@@ -20,7 +20,15 @@
import Divider from "@lib/components/Divider.svelte"
import ChannelMessage from "@app/components/ChannelMessage.svelte"
import ChannelCompose from "@app/components/ChannelCompose.svelte"
import {userMembership, decodeNRelay, makeChannelId, deriveChannel, GENERAL, tagRoom, MESSAGE} from "@app/state"
import {
userMembership,
decodeNRelay,
makeChannelId,
deriveChannel,
GENERAL,
tagRoom,
MESSAGE,
} from "@app/state"
import {addRoomMembership, removeRoomMembership} from "@app/commands"
const {nrelay, room = GENERAL} = $page.params