Add relay selection to note create screen

This commit is contained in:
Jonathan Staab 2023-02-08 09:04:17 -06:00
parent a8efa9ffc2
commit 9cac48b283
6 changed files with 130 additions and 31 deletions

View File

@ -33,6 +33,9 @@ If you like Coracle and want to support its development, you can donate sats via
# Missions
- [ ] Support paid relays
- atlas.nostr.land
- eden.nostr.land
- [ ] Image uploads
- Default will charge via lightning and have a tos, others can self-host and skip that.
- Add banner field to profile
@ -40,10 +43,9 @@ If you like Coracle and want to support its development, you can donate sats via
- https://github.com/brandonsavage/Upload
- https://github.com/seaweedfs/seaweedfs
- https://github.com/cubefs/cubefs
- [ ] Add relay selector when publishing a note
- [ ] Support relay auth
- [ ] Support invoices, tips, zaps https://twitter.com/jb55/status/1604131336247476224
- [ ] Separate settings for read, write, and broadcast relays based on NIP 65
- [ ] Deploy coracle relay
- [ ] Release to android with https://svelte-native.technology/docs
- [ ] Add no-relay gossip
- Capture certain events in a local db
@ -63,9 +65,10 @@ If you like Coracle and want to support its development, you can donate sats via
# Current
- [x] Re-design relays page and person relays list with metadata
- [ ] Add relay selection to new note screen
- [ ] Add relay selection to reply widget
- [ ] Switch from threshold to percentage, make it a setting
- [ ] Try switching to rxdb https://rxdb.info/
- [ ] Add modal for follows/followers
- [ ] Implement gossip model https://bountsr.org/code/2023/02/03/gossip-model.html
- [ ] Make feeds page customizable. This could potentially use the "lists" NIP
- [ ] Show notification at top of feeds: "Showing notes from 3 relays". Click to customize.
- [ ] Click through on relays page to view a feed for only that relay.
@ -81,6 +84,8 @@ If you like Coracle and want to support its development, you can donate sats via
- [x] Fix mention selection, inheritance, and inclusion in notes
- [x] Parse links without http at the beginning
- [x] Clean up back button in combination with modals
- [x] Re-design relays page and person relays list with metadata
- [x] Add relay selection to new note screen
## 0.2.9

View File

@ -2,7 +2,7 @@
import "@fortawesome/fontawesome-free/css/fontawesome.css"
import "@fortawesome/fontawesome-free/css/solid.css"
import {find, nthArg, pluck} from 'ramda'
import {find, identity, nthArg, pluck} from 'ramda'
import {onMount} from "svelte"
import {writable, get} from "svelte/store"
import {fly, fade} from "svelte/transition"
@ -51,11 +51,7 @@
const toggleSearch = () => searchIsOpen.update(x => !x)
const closeModal = async () => {
while ($modal) {
history.back()
await sleep(10)
}
modal.clear()
menuIsOpen.set(false)
}
@ -87,7 +83,7 @@
const interval = setInterval(() => {
alertSlowConnections()
retrieveRelayMeta()
}, 2_000)
}, 30_000)
const alertSlowConnections = () => {
// Only notify about relays the user is actually subscribed to
@ -113,6 +109,10 @@
const retrieveRelayMeta = async () => {
const {dufflepudUrl} = $settings
if (!dufflepudUrl) {
return
}
// Find relays with old/missing metadata and refresh them. Only pick a
// few so we're not sending too many concurrent http requests
const allRelays = await db.table('relays').toArray()
@ -122,19 +122,25 @@
const freshRelays = await Promise.all(
staleRelaysSample.map(async ({url}) => {
const res = await fetch(dufflepudUrl + '/relay/info', {
method: 'POST',
body: JSON.stringify({url}),
headers: {
'Content-Type': 'application/json',
},
})
try {
const res = await fetch(dufflepudUrl + '/relay/info', {
method: 'POST',
body: JSON.stringify({url}),
headers: {
'Content-Type': 'application/json',
},
})
return {...await res.json(), url, refreshed_at: now()}
return {...await res.json(), url, refreshed_at: now()}
} catch (e) {
console.warn(e)
return {url, refreshed_at: now()}
}
})
)
db.table('relays').bulkPut(freshRelays)
db.table('relays').bulkPut(freshRelays.filter(identity))
}
// Close menu on click outside

View File

@ -6,7 +6,7 @@ import {navigate} from "svelte-routing"
import {nip19} from 'nostr-tools'
import {writable, get} from "svelte/store"
import {globalHistory} from "svelte-routing/src/history"
import {synced} from "src/util/misc"
import {synced, sleep} from "src/util/misc"
// Routing
@ -49,6 +49,14 @@ export const modal = {
navigate(location.pathname)
}
},
close: () => modal.set(null),
clear: async () => {
// Reverse history so the back button doesn't bring our modal back up
while (get(modal)) {
history.back()
await sleep(30)
}
},
subscribe: cb => {
cb(last(modal.history))

View File

@ -1,9 +1,10 @@
<script>
import cx from 'classnames'
export let gap = 6
export let size = "2xl"
const className = "flex flex-col m-auto text-white gap-6"
const className = `flex flex-col m-auto text-white gap-${gap}`
if (!['inherit', 'lg', '2xl'].includes(size)) {
throw new Error(`Invalid size: ${size}`)

View File

@ -2,21 +2,29 @@
import {fly, fade} from "svelte/transition"
export let onEscape
export let nested = false
let root
</script>
<svelte:body
on:keydown={e => {
if (e.key === 'Escape') {
if (e.key === 'Escape' && !root.querySelector('.modal')) {
onEscape()
}
}} />
<div class="fixed inset-0 z-10">
<div class="fixed inset-0 z-10 modal" bind:this={root}>
<button
class="absolute inset-0 opacity-75 bg-black cursor-pointer"
class="absolute inset-0 bg-black cursor-pointer"
class:opacity-75={!nested}
class:opacity-25={nested}
transition:fade
on:click={onEscape} />
<div class="absolute inset-0 mt-20 sm:mt-28 modal-content" transition:fly={{y: 1000, opacity: 1}}>
<div
class="absolute inset-0 mt-20 sm:mt-28 modal-content"
transition:fly={{y: 1000, opacity: 1}}
style={nested && `padding-top: 1rem`}>
<dialog open class="bg-dark border-t border-solid border-medium h-full w-full overflow-auto">
<slot />
</dialog>

View File

@ -1,29 +1,62 @@
<script>
import {liveQuery} from 'dexie'
import {onMount} from "svelte"
import {quantify} from 'hurdak/lib/hurdak'
import {last, whereEq, find, reject, propEq} from 'ramda'
import {fly} from 'svelte/transition'
import {navigate} from "svelte-routing"
import {fuzzy} from "src/util/misc"
import Button from "src/partials/Button.svelte"
import Compose from "src/partials/Compose.svelte"
import Input from "src/partials/Input.svelte"
import RelayCardSimple from "src/partials/RelayCardSimple.svelte"
import Content from "src/partials/Content.svelte"
import Modal from "src/partials/Modal.svelte"
import Heading from 'src/partials/Heading.svelte'
import {user, getRelays} from "src/agent"
import {toast} from "src/app"
import {user, db, getRelays} from "src/agent"
import {toast, modal} from "src/app"
import cmd from "src/app/cmd"
let input = null
let relays = getRelays()
let showSettings = false
let q = ''
let search
const knownRelays = liveQuery(() => db.table('relays').toArray())
$: {
const data = reject(({url}) => find(whereEq({url}), relays), $knownRelays || [])
search = fuzzy(data, {keys: ["name", "description", "url"]})
}
const onSubmit = async () => {
const {content, mentions, topics} = input.parse()
if (content) {
await cmd.createNote(getRelays(), content, mentions, topics)
await cmd.createNote(relays, content, mentions, topics)
toast.show("info", `Your note has been created!`)
history.back()
modal.clear()
}
}
const closeSettings = () => {
q = ''
showSettings = false
}
const addRelay = relay => {
q = ''
relays = relays.concat(relay)
}
const removeRelay = relay => {
relays = reject(propEq('url', relay.url), relays)
}
onMount(() => {
if (!$user) {
navigate("/login")
@ -42,7 +75,45 @@
</div>
</div>
<Button type="submit" class="text-center">Send</Button>
<small
class="flex justify-end items-center gap-1 cursor-pointer"
on:click={() => { showSettings = true }}>
<span>Publishing to {quantify(relays.length, 'relay')}</span>
<i class="fa fa-edit" />
</small>
</div>
</Content>
</form>
{#if showSettings}
<Modal nested onEscape={closeSettings}>
<form on:submit|preventDefault={closeSettings}>
<Content>
<div class="flex justify-center items-center mb-4">
<Heading>Note relays</Heading>
</div>
<div>Select which relays to publish to:</div>
<div>
{#each relays as relay}
<div class="inline-block py-1 px-2 mr-1 mb-2 rounded-full border border-solid border-light">
<button type="button" class="fa fa-times cursor-pointer" on:click={() => removeRelay(relay)} />
{last(relay.url.split('//'))}
</div>
{/each}
</div>
<Input bind:value={q} placeholder="Search for other relays">
<i slot="before" class="fa fa-search" />
</Input>
{#each (q ? search(q) : []).slice(0, 3) as relay (relay.url)}
<RelayCardSimple {relay}>
<button slot="actions" class="underline" on:click={() => addRelay(relay)}>
Add relay
</button>
</RelayCardSimple>
{/each}
<Button type="submit" class="text-center">Done</Button>
</Content>
</form>
</Modal>
{/if}