Spiff up channels

This commit is contained in:
Jonathan Staab 2023-01-21 11:49:09 -08:00
parent ef3b7f2d3d
commit 07564ef29e
5 changed files with 79 additions and 46 deletions

View File

@ -17,7 +17,8 @@ If you like Coracle and want to support its development, you can donate sats via
- [x] Mentions
- [x] Persist and load relay list
- [x] NIP 05
- [ ] Direct messages using NIP 04
- [x] Direct messages using NIP 04
- [ ] Add petnames for channels
- [ ] Deploy coracle relay, set better defaults
- [ ] Image uploads
- Use dufflepud. Default will charge via lightning and have a tos, others can self-host and skip that.
@ -53,19 +54,9 @@ If you like Coracle and want to support its development, you can donate sats via
- [ ] Figure out migrations from previous version
- [ ] Fix notes search
- [ ] Chat
- [ ] Figure out which relays to use
- [ ] Add petnames for channels
- [ ] Add back button
- [ ] Create Room -> open modal, choose dm or public room
- [x] Add DM button to profile pages
- [ ] Linkify bech32 entities
- [ ] linkify dm page header
- [ ] Add lock/unlock icon to channel header
- [ ] Add notification for dms
- [ ] Default to network/following
- [ ] Add analytics
- [ ] Allow disabling error reporting/analytics
## 0.2.7
@ -97,6 +88,8 @@ If you like Coracle and want to support its development, you can donate sats via
- [x] Added error tracking with bugsnag
- [x] Upgraded nostr-tools
- [x] Added support for NIP-05 verfication
- [x] Added analytics and error reporting (opt out supported)
- [x] Added direct messages and group chat
## 0.2.6

View File

@ -1,5 +1,5 @@
import Bugsnag from "@bugsnag/js"
import {prop, nthArg} from "ramda"
import {prop} from "ramda"
import {uuid} from "hurdak/lib/hurdak"
import {navigate} from "svelte-routing"
import {nip19} from 'nostr-tools'

View File

@ -6,11 +6,13 @@
import {prop, path as getPath, reverse, uniqBy, sortBy, last} from 'ramda'
import {formatTimestamp, sleep, createScroller, Cursor} from 'src/util/misc'
import Badge from 'src/partials/Badge.svelte'
import Anchor from 'src/partials/Anchor.svelte'
import Spinner from 'src/partials/Spinner.svelte'
import {user, getPerson} from 'src/agent'
import {render} from 'src/app'
export let name
export let link
export let about
export let picture
export let loadMessages
@ -18,11 +20,10 @@
export let sendMessage
export let editRoom = null
export let type
console.log(editRoom)
let textarea
let messages = []
let loading = sleep(10_000)
let loading = sleep(30_000)
let annotatedMessages = []
let showNewMessages = false
let cursor = new Cursor()
@ -64,14 +65,14 @@
return navigate('/login')
}
const sub = listenForMessages(
const sub = await listenForMessages(
newMessages => stickToBottom('smooth', () => {
loading = sleep(10_000)
loading = sleep(30_000)
messages = messages.concat(newMessages)
})
)
const scroller = createScroller(
const scroller = await createScroller(
async () => {
const events = await loadMessages(cursor)
@ -79,7 +80,7 @@
cursor.onChunk(events)
stickToBottom('auto', () => {
loading = sleep(10_000)
loading = sleep(30_000)
messages = events.concat(messages)
})
}
@ -121,8 +122,8 @@
<div class="flex gap-4 h-full">
<div class="relative w-full">
<div class="flex flex-col py-32 h-full">
<ul class="p-4 h-full flex-grow flex flex-col-reverse justify-start" name="messages">
<div class="flex flex-col pt-20 pb-28 h-full">
<ul class="pb-6 p-4 overflow-auto flex-grow flex flex-col-reverse justify-start" name="messages">
{#each annotatedMessages as m (m.id)}
<li in:fly={{y: 20}} class="py-1 flex flex-col gap-2">
{#if type === 'chat' && m.showPerson}
@ -143,22 +144,42 @@
{/each}
{#await loading}
<Spinner>Looking for messages...</Spinner>
{:then}
<div in:fly={{y: 20}} class="text-center py-20">End of message history</div>
{/await}
</ul>
</div>
<div class="fixed z-10 top-16 w-full lg:-ml-56 lg:pl-56 border-b border-solid border-medium bg-dark">
<div class="p-4 flex gap-4">
<div
class="overflow-hidden w-12 h-12 rounded-full bg-cover bg-center shrink-0 border border-solid border-white"
style="background-image: url({picture})" />
<div class="w-full">
<div class="flex items-center gap-4">
<i class="fa fa-arrow-left text-2xl cursor-pointer" on:click={() => navigate("/chat")} />
<div
class="overflow-hidden w-12 h-12 rounded-full bg-cover bg-center shrink-0 border border-solid border-white"
style="background-image: url({picture})" />
</div>
<div class="w-full flex flex-col gap-2">
<div class="flex items-center justify-between w-full">
<div class="text-lg font-bold">{name || ''}</div>
{#if editRoom}
<small class="cursor-pointer" on:click={editRoom}>
<i class="fa-solid fa-edit" /> Edit
</small>
{/if}
<div class="flex items-center gap-4">
{#if link}
<Anchor type="unstyled" href={link} class="text-lg font-bold">{name || ''}</Anchor>
{:else}
<div class="text-lg font-bold">{name || ''}</div>
{/if}
{#if editRoom}
<small class="cursor-pointer" on:click={editRoom}>
<i class="fa-solid fa-edit" /> Edit
</small>
{/if}
</div>
<div class="flex items-center gap-2">
{#if type === 'dm'}
<i class="fa fa-lock text-light" />
<span class="text-light">Encrypted</span>
{:else}
<i class="fa fa-lock-open text-light" />
<span class="text-light">Public</span>
{/if}
</div>
</div>
<div>{about || ''}</div>
</div>

View File

@ -4,7 +4,7 @@
import {nip19} from 'nostr-tools'
import {now, batch} from 'src/util/misc'
import Channel from 'src/partials/Channel.svelte'
import {getRelays, db, listen, load} from 'src/agent'
import {getRelays, user, db, listen, load} from 'src/agent'
import {modal} from 'src/app'
import loaders from 'src/app/loaders'
import cmd from 'src/app/cmd'
@ -14,25 +14,42 @@
let {data: roomId} = nip19.decode(entity)
let room = liveQuery(() => db.rooms.where('id').equals(roomId).first())
const listenForMessages = cb => listen(
getRelays(),
// Listen for updates to the room in case we didn't get them before
[{kinds: [40, 41], ids: [roomId]},
{kinds: [42], '#e': [roomId], since: now()}],
batch(300, events => {
const newMessages = events.filter(e => e.kind === 42)
const getRoomRelays = $room => {
let relays = getRelays()
loaders.loadPeople(getRelays(), pluck('pubkey', events))
if ($room) {
relays = relays.concat(getRelays($room.pubkey))
}
cb(newMessages)
})
)
return relays
}
const listenForMessages = async cb => {
// Make sure we have our room so we can calculate relays
const $room = await db.rooms.where('id').equals(roomId).first()
const relays = getRoomRelays($room)
return listen(
relays,
// Listen for updates to the room in case we didn't get them before
[{kinds: [40, 41], ids: [roomId]},
{kinds: [42], '#e': [roomId], since: now()}],
batch(300, events => {
const newMessages = events.filter(e => e.kind === 42)
loaders.loadPeople(relays, pluck('pubkey', events))
cb(newMessages)
})
)
}
const loadMessages = async ({until, limit}) => {
const events = await load(getRelays(), {kinds: [42], '#e': [roomId], until, limit})
const relays = getRoomRelays($room)
const events = await load(relays, {kinds: [42], '#e': [roomId], until, limit})
if (events.length) {
await loaders.loadPeople(getRelays(), pluck('pubkey', events))
await loaders.loadPeople(relays, pluck('pubkey', events))
}
return events
@ -51,8 +68,8 @@
name={$room?.name}
about={$room?.about}
picture={$room?.picture}
editRoom={$room?.pubkey === $user.pubkey && editRoom}
{loadMessages}
{listenForMessages}
{sendMessage}
{editRoom}
/>

View File

@ -6,6 +6,7 @@
import {batch} from 'src/util/misc'
import Channel from 'src/partials/Channel.svelte'
import {getRelays, user, db, listen, keys} from 'src/agent'
import {routes} from 'src/app/ui'
import cmd from 'src/app/cmd'
export let entity
@ -26,7 +27,7 @@
}
const listenForMessages = cb => listen(
getRelays(),
getRelays().concat(getRelays(pubkey)),
[{kinds: personKinds, authors: [pubkey]},
{kinds: [4], authors: [$user.pubkey], '#p': [pubkey]},
{kinds: [4], authors: [pubkey], '#p': [$user.pubkey]}],
@ -62,6 +63,7 @@
name={$person?.name}
about={$person?.about}
picture={$person?.picture}
link={$person ? routes.person($person.pubkey) : null}
{loadMessages}
{listenForMessages}
{sendMessage}