Clean up Relay Card and onboarding data

This commit is contained in:
Jonathan Staab 2023-04-18 14:38:18 -05:00
parent c22e4e76a9
commit 6c0eab5214
18 changed files with 111 additions and 118 deletions

View File

@ -1,6 +1,6 @@
# Current
- [ ] Check on RelayCard, it should automatically do the right thing for anon/pubkey
- [ ] Details on note in modal is broken
- [ ] Remember message/chat status
- [ ] Image classification
- https://github.com/bhky/opennsfw2

View File

@ -94,6 +94,13 @@ const Meta = {
const forceUrls = (import.meta.env.VITE_FORCE_RELAYS || "").split(",").filter(identity)
const defaultUrls = [
"wss://nostr-pub.wellorder.net",
"wss://nostr.zebedee.cloud",
"wss://nos.lol",
"wss://brb.io",
]
const getUrls = relays => {
if (relays.length === 0) {
error(`Attempted to connect to zero urls`)
@ -370,6 +377,7 @@ export default {
Config,
Meta,
forceUrls,
defaultUrls,
disconnect,
getQuality,
publish,

View File

@ -185,6 +185,11 @@ export const sampleRelays = (relays, scale = 1) => {
relays = relays.concat(shuffle(getUserReadRelays()).slice(0, limit - relays.length))
}
// And if we still have nothing, add a default
if (relays.length === 0) {
relays = [{url: pool.forceUrls[0] || pool.defaultUrls[0]}]
}
return uniqByUrl(relays)
}

View File

@ -3,6 +3,13 @@ import {Tags} from "src/util/nostr"
import {getPersonWithFallback} from "src/agent/db"
import user from "src/agent/user"
export const defaultFollows = [
"97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322", // hodlbod
"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", // fiatjaf
"82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2", // jack
"6e468422dfb74a5738702a8823b9b28168abab8655faacb6853cd0ee15deee93", // Gigi
]
export const getFollows = pubkey =>
Tags.wrap(getPersonWithFallback(pubkey).petnames).type("p").values().all()

View File

@ -88,6 +88,7 @@ export default {
petnames,
getPetnames: () => profileCopy.petnames,
petnamePubkeys: derived(petnames, map(nth(1))) as Readable<Array<string>>,
getPetnamePubkeys: () => profileCopy.petnames.map(nth(1)),
updatePetnames(f) {
const $petnames = f(profileCopy.petnames)

View File

@ -32,7 +32,7 @@
{/if}
<div class="flex flex-col gap-2">
{#each $relays as relay (relay.url)}
<RelayCard showActions {relay} />
<RelayCard {relay} />
{:else}
<div class="flex flex-col items-center gap-4 my-8">
<div class="text-xl flex gap-2 items-center">
@ -45,7 +45,7 @@
</div>
<RelaySearch>
<div slot="item" let:relay>
<RelayCard showActions {relay} />
<RelayCard {relay} />
</div>
</RelaySearch>
</Content>

View File

@ -312,7 +312,7 @@
<p>This note was found on {quantify(note.seen_on.length, "relay")} below.</p>
<div class="flex flex-col gap-2">
{#each note.seen_on as url}
<RelayCard theme="black" relay={{url}} />
<RelayCard relay={{url}} />
{/each}
</div>
<h1 class="staatliches text-2xl">Details</h1>

View File

@ -14,9 +14,9 @@
export let person
export let hasPetname = null
export let removePetname = ({pubkey}) => user.removePetname(pubkey)
const removePetname = ({pubkey}) => user.removePetname(pubkey)
export let addPetname = ({pubkey}) => {
const addPetname = ({pubkey}) => {
const [{url}] = sampleRelays(getPubkeyWriteRelays(pubkey))
user.addPetname(pubkey, url, displayPerson(person))

View File

@ -16,9 +16,7 @@
<div class="pt-8 text-center">No relays found</div>
{:else}
{#each relays as relay (relay.url)}
{#if relay.write !== "!"}
<RelayCard {relay} />
{/if}
<RelayCard {relay} />
{/each}
{/if}
</Content>

View File

@ -14,7 +14,7 @@
export let relay
export let theme = "gray-8"
export let showStatus = false
export let showActions = false
export let hideActions = false
export let showControls = false
const {relays, canPublish} = user
@ -23,11 +23,11 @@
let quality = null
let message = null
export let hasRelay = r => Boolean(find(propEq("url", r.url), $relays))
$: hasRelay = Boolean(find(propEq("url", relay.url), $relays))
export let removeRelay = r => user.removeRelay(r.url)
const removeRelay = r => user.removeRelay(r.url)
export let addRelay = r => {
const addRelay = r => {
user.addRelay(r.url)
const pubkey = user.getPubkey()
@ -79,17 +79,16 @@
</p>
{/if}
</div>
{#if showActions}
{#if !hideActions}
<slot name="actions">
{#if hasRelay(relay) && $relays.length > 1}
<button class="flex items-center gap-3 text-gray-1" on:click={() => removeRelay(relay)}>
<i class="fa fa-right-from-bracket" /> Leave
</button>
{/if}
{#if !hasRelay(relay)}
{#if !hasRelay}
<button class="flex items-center gap-3 text-gray-1" on:click={() => addRelay(relay)}>
<i class="fa fa-right-to-bracket" /> Join
</button>
{:else if $relays.length > 1}
<button class="flex items-center gap-3 text-gray-1" on:click={() => removeRelay(relay)}>
<i class="fa fa-right-from-bracket" /> Leave
</button>
{/if}
</slot>
{/if}
@ -97,7 +96,8 @@
{#if relay.description}
<p>{relay.description}</p>
{/if}
{#if hasRelay(relay) && showControls && $canPublish}
{#if hasRelay && showControls && $canPublish}
<div class="-mx-6 my-1 h-px bg-gray-7" />
<div class="flex justify-between gap-2">
<span>Publish to this relay?</span>
<Toggle

View File

@ -122,7 +122,7 @@
{#each Object.values(currentRelays) as relay}
<div class="h-12">
{#if relay}
<RelayCard relay={{...relay, description: null}} />
<RelayCard hideActions relay={{...relay, description: null}} />
{/if}
</div>
{/each}

View File

@ -151,7 +151,7 @@
</div>
<RelaySearch bind:q limit={3} hideIfEmpty>
<div slot="item" let:relay>
<RelayCard {relay} showActions>
<RelayCard {relay}>
<button
slot="actions"
class="underline"

View File

@ -1,5 +1,5 @@
<script lang="ts">
import {uniq, objOf} from "ramda"
import {uniq} from "ramda"
import {onMount} from "svelte"
import {generatePrivateKey} from "nostr-tools"
import {fly} from "svelte/transition"
@ -11,11 +11,10 @@
import OnboardingRelays from "src/app/views/OnboardingRelays.svelte"
import OnboardingFollows from "src/app/views/OnboardingFollows.svelte"
import OnboardingComplete from "src/app/views/OnboardingComplete.svelte"
import {getFollows} from "src/agent/social"
import {getFollows, defaultFollows} from "src/agent/social"
import {getPubkeyWriteRelays, sampleRelays} from "src/agent/relays"
import {getPersonWithFallback} from "src/agent/db"
import network from "src/agent/network"
import pool from "src/agent/pool"
import user from "src/agent/user"
import keys from "src/agent/keys"
import {loadAppData} from "src/app/state"
@ -23,39 +22,15 @@
export let stage
const {relays: userRelays, petnamePubkeys} = user
let relays = []
if ($userRelays.length > 0) {
relays = $userRelays
} else if (pool.forceUrls.length > 0) {
relays = pool.forceUrls.map(objOf("url"))
} else {
relays = [
{url: "wss://nostr-pub.wellorder.net", write: true},
{url: "wss://nostr.zebedee.cloud", write: true},
{url: "wss://nos.lol", write: true},
{url: "wss://brb.io", write: true},
]
}
let follows =
$petnamePubkeys.length > 0
? $petnamePubkeys
: [
"97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322", // hodlbod
"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", // fiatjaf
"82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2", // jack
"6e468422dfb74a5738702a8823b9b28168abab8655faacb6853cd0ee15deee93", // Gigi
]
const privkey = generatePrivateKey()
const signup = async () => {
await keys.login("privkey", privkey)
await user.updateRelays(() => relays)
// Re-save preferences now that we have a key
await user.updateRelays(() => user.getRelays())
await user.updatePetnames(() =>
follows.map(pubkey => {
user.getPetnamePubkeys().map(pubkey => {
const [{url}] = sampleRelays(getPubkeyWriteRelays(pubkey))
const name = displayPerson(getPersonWithFallback(pubkey))
@ -65,12 +40,15 @@
loadAppData(user.getPubkey())
modal.pop()
modal.clear()
navigate("/notes")
}
// Prime our people cache for hardcoded follows and a sample of people they follow
onMount(async () => {
const relays = sampleRelays(user.getRelays())
const follows = user.getPetnamePubkeys().concat(defaultFollows)
await network.loadPeople(follows, {relays})
const others = shuffle(uniq(follows.flatMap(getFollows))).slice(0, 256)
@ -86,9 +64,9 @@
{:else if stage === "key"}
<OnboardingKey {privkey} />
{:else if stage === "relays"}
<OnboardingRelays bind:relays />
<OnboardingRelays />
{:else if stage === "follows"}
<OnboardingFollows bind:follows />
<OnboardingFollows />
{:else}
<OnboardingComplete {signup} />
{/if}

View File

@ -1,34 +1,33 @@
<script lang="ts">
import {without, always} from "ramda"
import {fuzzy} from "src/util/misc"
import {reject} from "ramda"
import {displayPerson} from "src/util/nostr"
import Input from "src/partials/Input.svelte"
import Anchor from "src/partials/Anchor.svelte"
import Heading from "src/partials/Heading.svelte"
import Content from "src/partials/Content.svelte"
import PersonInfo from "src/app/shared/PersonInfo.svelte"
import {getPersonWithFallback} from "src/agent/db"
import {watch} from "src/agent/db"
import {getPersonWithFallback, searchPeople} from "src/agent/db"
import {defaultFollows} from "src/agent/social"
import {sampleRelays, getPubkeyWriteRelays} from "src/agent/relays"
import {modal} from "src/partials/state"
import user from "src/agent/user"
export let follows
const {petnamePubkeys} = user
if ($petnamePubkeys.length === 0) {
user.updatePetnames(() =>
defaultFollows.map(pubkey => {
const [{url}] = sampleRelays(getPubkeyWriteRelays(pubkey))
const name = displayPerson(getPersonWithFallback(pubkey))
return ["p", pubkey, url, name]
})
)
}
let q = ""
let search
const knownPeople = watch("people", t => t.all({"kind0.name": {$type: "string"}}))
$: search = fuzzy(
$knownPeople.filter(p => !follows.includes(p.pubkey)),
{keys: ["kind0.name", "kind0.about", "pubkey"]}
)
const removePetname = ({pubkey}) => {
follows = without([pubkey], follows)
}
const addPetname = ({pubkey}) => {
follows = follows.concat(pubkey)
}
$: results = reject(p => $petnamePubkeys.includes(p.pubkey), $searchPeople(q))
</script>
<Content>
@ -40,7 +39,7 @@
</p>
<Anchor
type="button-accent"
on:click={() => modal.push({type: "onboarding", stage: "complete"})}>
on:click={() => modal.replace({type: "onboarding", stage: "complete"})}>
Continue
</Anchor>
</Content>
@ -48,17 +47,14 @@
<i class="fa fa-user-astronaut fa-lg" />
<h2 class="staatliches text-2xl">Your follows</h2>
</div>
{#if follows.length === 0}
{#if $petnamePubkeys.length === 0}
<div class="mt-8 flex items-center justify-center gap-2 text-center">
<i class="fa fa-triangle-exclamation" />
<span>No follows selected</span>
</div>
{:else}
{#each follows as pubkey}
<PersonInfo
person={getPersonWithFallback(pubkey)}
hasPetname={always(true)}
{removePetname} />
{#each $petnamePubkeys as pubkey}
<PersonInfo person={getPersonWithFallback(pubkey)} />
{/each}
{/if}
<div class="flex items-center gap-2">
@ -68,7 +64,7 @@
<Input bind:value={q} type="text" wrapperClass="flex-grow" placeholder="Type to search">
<i slot="before" class="fa-solid fa-search" />
</Input>
{#each search(q).slice(0, 50) as person (person.pubkey)}
<PersonInfo {person} hasPetname={always(false)} {addPetname} />
{#each results.slice(0, 50) as person (person.pubkey)}
<PersonInfo {person} />
{/each}
</Content>

View File

@ -19,7 +19,7 @@
When youre ready to dive in, click below and well guide you through the process of creating an
account.
</p>
<Anchor type="button-accent" on:click={() => modal.push({type: "onboarding", stage: "key"})}>
<Anchor type="button-accent" on:click={() => modal.replace({type: "onboarding", stage: "key"})}>
Let's go!
</Anchor>
</Content>

View File

@ -32,7 +32,7 @@
</Input>
<Anchor
type="button-accent"
on:click={() => modal.push({type: "onboarding", stage: nextStage})}>
on:click={() => modal.replace({type: "onboarding", stage: nextStage})}>
Log in
</Anchor>
</div>

View File

@ -1,5 +1,5 @@
<script lang="ts">
import {reject, always, pluck, propEq} from "ramda"
import {pluck} from "ramda"
import {fuzzy} from "src/util/misc"
import {modal} from "src/partials/state"
import Input from "src/partials/Input.svelte"
@ -8,23 +8,26 @@
import Content from "src/partials/Content.svelte"
import RelayCard from "src/app/shared/RelayCard.svelte"
import {watch} from "src/agent/db"
import pool from "src/agent/pool"
import user from "src/agent/user"
export let relays
const {relays} = user
if ($relays.length === 0) {
user.updateRelays(() =>
(pool.forceUrls.length > 0 ? pool.forceUrls : pool.defaultUrls).map(url => ({
url,
write: true,
}))
)
}
let q = ""
let search
const knownRelays = watch("relays", t => t.all())
const removeRelay = r => {
relays = reject(propEq("url", r.url), relays)
}
const addRelay = r => {
relays = relays.concat({...r, write: true})
}
$: joined = new Set(pluck("url", relays))
$: joined = new Set(pluck("url", $relays))
$: search = fuzzy(
$knownRelays.filter(r => !joined.has(r.url)),
{keys: ["name", "description", "url"]}
@ -32,32 +35,33 @@
</script>
<Content>
<Content class="text-center">
<div class="text-center">
<Heading>Get Connected</Heading>
<p>
Nostr is a protocol, not a platform. This means that <i>you</i> choose where to store your data.
Select your preferred storage relays below, or click "continue" to use some reasonable defaults.
You can change your selection any time.
</p>
<Anchor
type="button-accent"
on:click={() => modal.push({type: "onboarding", stage: "follows"})}>
Continue
</Anchor>
</Content>
</div>
<Anchor
type="button-accent"
class="text-center"
on:click={() => modal.replace({type: "onboarding", stage: "follows"})}>
Continue
</Anchor>
<div class="flex items-center gap-2">
<i class="fa fa-server fa-lg" />
<h2 class="staatliches text-2xl">Your relays</h2>
</div>
{#if relays.length === 0}
{#if $relays.length === 0}
<div class="mt-8 flex items-center justify-center gap-2 text-center">
<i class="fa fa-triangle-exclamation" />
<span>No relays connected</span>
</div>
{:else}
<div class="grid grid-cols-1 gap-4">
{#each relays as relay (relay.url)}
<RelayCard {relay} hasRelay={always(true)} {removeRelay} />
{#each $relays as relay (relay.url)}
<RelayCard {relay} />
{/each}
</div>
{/if}
@ -69,10 +73,10 @@
<i slot="before" class="fa-solid fa-search" />
</Input>
{#each (search(q) || []).slice(0, 50) as relay (relay.url)}
<RelayCard {relay} hasRelay={always(false)} {addRelay} />
<RelayCard {relay} />
{/each}
<small class="text-center">
Showing {Math.min($knownRelays.length - relays.length, 50)}
of {$knownRelays.length - relays.length} known relays
Showing {Math.min($knownRelays.length - $relays.length, 50)}
of {$knownRelays.length - $relays.length} known relays
</small>
</Content>

View File

@ -35,7 +35,7 @@
{/if}
<div class="grid grid-cols-1 gap-4">
{#each $relays as relay (relay.url)}
<RelayCard showActions showControls {relay} />
<RelayCard showControls {relay} />
{/each}
</div>
<div class="flex flex-col gap-6" in:fly={{y: 20}}>
@ -48,11 +48,7 @@
Coracle automatically discovers relays as you browse the network. Adding more relays will
generally make things quicker to load, at the expense of higher data usage.
</p>
<RelaySearch>
<div slot="item" let:relay>
<RelayCard showActions {relay} />
</div>
</RelaySearch>
<RelaySearch />
</div>
</Content>
</div>