Finishing touches

This commit is contained in:
Jonathan Staab 2022-12-23 15:25:51 -08:00
parent 46d2a52e67
commit 30270d331c
16 changed files with 67 additions and 44 deletions

View File

@ -34,18 +34,7 @@ Coracle is currently in _alpha_ - expect bugs, slow loading times, and rough edg
# Current update
- [ ] Re-implement muffle
- Don't store muffled events, when muffle changes delete them
- [ ] Delete old events
- [ ] Make sure login/out, no user usage works
- [ ] Add a re-sync/clear cache button
- [ ] Note detail context not showing when navigating between note details (e.g. to parent)
- [ ] Show reply to on feed
- [ ] Write blog post
- https://vitejs.dev/guide/features.html#web-workers
- https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
- https://web.dev/module-workers/
- [x] Sync user
- [x] Based on petnames, sync network to 2 or 3 degrees of separation
- When a user is added/removed, sync them and add to or remove from network

View File

@ -162,12 +162,12 @@
{/if}
</a>
</li>
{/if}
<li class="cursor-pointer">
<a class="block px-4 py-2 hover:bg-accent transition-all" href="/search/people">
<i class="fa-solid fa-search mr-2" /> Search
</a>
</li>
{/if}
<li class="cursor-pointer">
<a class="block px-4 py-2 hover:bg-accent transition-all" href="/notes/network">
<i class="fa-solid fa-tag mr-2" /> Notes

View File

@ -16,7 +16,6 @@
export let note
export let depth = 0
export let anchorId = null
export let showParent = false
export let invertColors = false
let reply = null
@ -118,7 +117,7 @@
<p class="text-sm text-light">{formatTimestamp(note.created_at)}</p>
</div>
<div class="ml-6 flex flex-col gap-2">
{#if findReply(note) && showParent}
{#if findReply(note)}
<small class="text-light">
Reply to <Anchor on:click={goToParent}>{findReply(note).slice(0, 8)}</Anchor>
</small>

View File

@ -6,7 +6,6 @@
import relay from 'src/relay'
export let loadNotes
export let showParent = false
let notes
let limit = 0
@ -25,7 +24,7 @@
{#if notes}
<ul class="py-4 flex flex-col gap-2 max-w-xl m-auto">
{#each ($notes || []) as n (n.id)}
<li><Note note={n} depth={2} {showParent} /></li>
<li><Note note={n} depth={2} /></li>
{/each}
</ul>
{/if}

View File

@ -2,15 +2,15 @@ import Dexie from 'dexie'
import {writable, get} from 'svelte/store'
import {groupBy, prop, flatten, pick} from 'ramda'
import {ensurePlural, switcherFn} from 'hurdak/lib/hurdak'
import {now, getLocalJson, setLocalJson} from 'src/util/misc'
import {now, timedelta, getLocalJson, setLocalJson} from 'src/util/misc'
import {filterTags, findReply, findRoot} from 'src/util/nostr'
export const db = new Dexie('coracle/relay')
db.version(4).stores({
db.version(5).stores({
relays: '++url, name',
events: '++id, pubkey, created_at, kind, content, reply, root',
tags: '++key, event, value',
tags: '++key, event, value, created_at',
})
window.db = db
@ -39,7 +39,7 @@ db.events.process = async events => {
// Persist notes and reactions
if (notesAndReactions.length > 0) {
const persistentEvents = notesAndReactions
.map(e => ({...e, root: findRoot(e), reply: findReply(e), added_at: now()}))
.map(e => ({...e, root: findRoot(e), reply: findReply(e), created_at: now()}))
db.events.bulkPut(persistentEvents)
@ -54,6 +54,7 @@ db.events.process = async events => {
value: tag[1],
relay: tag[2],
mark: tag[3],
created_at: e.created_at,
})
)
)
@ -102,3 +103,9 @@ db.events.process = async events => {
return $people
})
}
// On initial load, delete old event data
const threshold = now() - timedelta(30, 'days')
db.events.where('created_at').below(threshold).delete()
db.tags.where('created_at').below(threshold).delete()

View File

@ -1,6 +1,6 @@
import {liveQuery} from 'dexie'
import {get} from 'svelte/store'
import {pluck, take, uniqBy, groupBy, concat, without, prop, isNil, identity} from 'ramda'
import {pluck, uniq, take, uniqBy, groupBy, concat, without, prop, isNil, identity} from 'ramda'
import {ensurePlural, createMap, ellipsize} from 'hurdak/lib/hurdak'
import {escapeHtml} from 'src/util/html'
import {filterTags, findReply, findRoot} from 'src/util/nostr'
@ -216,9 +216,17 @@ const loadNoteContext = async (note, {loadParent = false} = {}) => {
filter.push({kinds: [0], authors: [note.pubkey]})
}
await pool.loadEvents(filter)
const replyId = findReply(note)
// Load the events
const events = await pool.loadEvents(filter)
// Load any related people we're missing
const $people = get(people)
await pool.loadPeople(
uniq(pluck('pubkey', events)).filter(k => !$people[k])
)
// Load the note's parent
const replyId = findReply(note)
if (loadParent && replyId) {
await getOrLoadNote(replyId)
}

View File

@ -207,5 +207,5 @@ const syncNetwork = async () => {
export default {
getPubkey, getRelays, addRelay, removeRelay, setPrivateKey, setPublicKey,
publishEvent, loadEvents, listenForEvents, syncNetwork,
publishEvent, loadEvents, listenForEvents, syncNetwork, loadPeople,
}

View File

@ -103,7 +103,7 @@
{#if e.people}
<li in:fly={{y: 20}}><Like note={e} /></li>
{:else}
<li in:fly={{y: 20}}><Note showParent note={e} /></li>
<li in:fly={{y: 20}}><Note note={e} /></li>
{/if}
{/each}
</ul>

View File

@ -63,15 +63,17 @@
<div class="flex flex-col gap-4 max-w-2xl">
<div class="flex justify-center items-center flex-col mb-4">
<h1 class="staatliches text-6xl">Welcome!</h1>
<i>To the Dogwood Social Network</i>
<i>To the Nostr Protocol Network</i>
</div>
<div class="flex flex-col gap-4">
<small>
To log in to existing account, simply enter your private key. To create a new account, just
let us generate one for you. You can also use
a <Anchor href={nip07} external>compatible browser extension</Anchor> to
sign events without having to paste your private key here.
</small>
<p>
To log in to existing account, simply enter your private key below. To create a new account,
just let us generate one for you.
</p>
<p>
You can also use a <Anchor href={nip07} external>compatible browser extension</Anchor> to
sign events without having to paste your private key here (recommended).
</p>
<div class="flex flex-col gap-1">
<strong>Private Key</strong>
<Input type="password" bind:value={privkey} placeholder="Enter your private key">

View File

@ -4,7 +4,7 @@
import Tabs from "src/partials/Tabs.svelte"
import Network from "src/views/notes/Network.svelte"
import Global from "src/views/notes/Global.svelte"
import {connections} from 'src/relay'
import {connections, user} from 'src/relay'
export let activeTab
@ -19,7 +19,7 @@
> to get started.
</div>
</div>
{:else}
{:else if $user}
<Tabs tabs={['network', 'global']} {activeTab} {setActiveTab} />
{#if activeTab === 'network'}
<Network />
@ -34,5 +34,12 @@
<span class="fa-sold fa-plus fa-2xl" />
</a>
</div>
{:else}
<div class="flex w-full justify-center items-center py-16">
<div class="text-center max-w-sm">
Don't have an account? Click <Anchor href="/login">here</Anchor> to join the nostr network.
</div>
</div>
<Global />
{/if}

View File

@ -111,7 +111,7 @@
<Tabs tabs={['notes', 'likes', 'network']} {activeTab} {setActiveTab} />
{#if activeTab === 'notes'}
<Notes showParent loadNotes={loadNotes} />
<Notes loadNotes={loadNotes} />
{:else if activeTab === 'likes'}
<Notes loadNotes={loadLikes} />
{:else if activeTab === 'network'}

View File

@ -100,7 +100,7 @@ export const getLastSync = (k, fallback) => {
export class Cursor {
constructor(since, delta) {
this.since = since || now() - delta,
this.since = (since || now()) - delta,
this.delta = delta
}
step() {

View File

@ -47,7 +47,7 @@
</div>
{:else if $observable}
<div n:fly={{y: 20}}>
<Note showParent invertColors anchorId={note.id} note={$observable} depth={2} />
<Note invertColors anchorId={note.id} note={$observable} depth={2} />
</div>
{:else}
<Spinner />

View File

@ -4,7 +4,6 @@
import {fly} from 'svelte/transition'
import Button from "src/partials/Button.svelte"
import SelectButton from "src/partials/SelectButton.svelte"
import {getTagValues} from "src/util/nostr"
import {modal} from "src/state/app"
import relay, {user} from 'src/relay'

View File

@ -3,6 +3,7 @@
import {onMount, onDestroy} from 'svelte'
import Notes from "src/partials/Notes.svelte"
import {timedelta, Cursor, getLastSync} from 'src/util/misc'
import {getTagValues} from 'src/util/nostr'
import relay, {user} from 'src/relay'
let sub

View File

@ -3,24 +3,33 @@
import {onMount, onDestroy} from 'svelte'
import Notes from "src/partials/Notes.svelte"
import {timedelta, Cursor, getLastSync} from 'src/util/misc'
import {getTagValues} from 'src/util/nostr'
import relay, {user, network} from 'src/relay'
let sub
let networkUnsub
const cursor = new Cursor(
getLastSync('views/notes/Network'),
timedelta(1, 'hours')
)
onMount(async () => {
sub = await relay.pool.listenForEvents(
'views/notes/Network',
[{kinds: [1, 5, 7], authors: $network, since: cursor.since}],
when(propEq('kind', 1), relay.loadNoteContext)
)
onMount(() => {
// We need to re-create the sub when network changes, since this is where
// we land when we first log in, but before network is loaded, leading to
// a forever spinner.
networkUnsub = network.subscribe(async $network => {
sub = await relay.pool.listenForEvents(
'views/notes/Network',
[{kinds: [1, 5, 7], authors: $network, since: cursor.since}],
when(propEq('kind', 1), relay.loadNoteContext)
)
})
})
onDestroy(() => {
networkUnsub()
if (sub) {
sub.unsub()
}
@ -46,4 +55,7 @@
}
</script>
<!-- hack to reload notes when our network initiall loads, see onMount -->
{#key $network.map(n => n[0]).join('')}
<Notes shouldMuffle loadNotes={loadNotes} />
{/key}