mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-30 00:41:12 +00:00
Add search page
This commit is contained in:
parent
4b59484cb7
commit
f5b5e851f7
@ -1,5 +1,7 @@
|
||||
Bugs
|
||||
|
||||
- [ ] Scale rather than fly reply box
|
||||
- [ ] Listener on notes view not adding notes
|
||||
- [ ] Pin joined relays at the top
|
||||
- [ ] Load/publish user preferred relays
|
||||
- [ ] Optimistically load events the user publishes (e.g. to reduce reflow for reactions/replies). Essentially, we can pretend to be our own in-memory relay.
|
||||
@ -9,7 +11,8 @@ Features
|
||||
- [x] Chat
|
||||
- [x] Threads/social
|
||||
- [ ] Search
|
||||
- [ ] Followers
|
||||
- [ ] Followers, blocking
|
||||
- [ ] Notifications
|
||||
- [ ] Server discovery
|
||||
- [ ] Favorite chat rooms
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
import Anchor from 'src/partials/Anchor.svelte'
|
||||
import NoteDetail from "src/partials/NoteDetail.svelte"
|
||||
import NotFound from "src/routes/NotFound.svelte"
|
||||
import Search from "src/routes/Search.svelte"
|
||||
import Notes from "src/routes/Notes.svelte"
|
||||
import Login from "src/routes/Login.svelte"
|
||||
import Profile from "src/routes/Profile.svelte"
|
||||
@ -75,6 +76,7 @@
|
||||
<Router {url}>
|
||||
<div use:links class="h-full">
|
||||
<div class="pt-16 text-white h-full">
|
||||
<Route path="/search" component={Search} />
|
||||
<Route path="/notes" component={Notes} />
|
||||
<Route path="/notes/new" component={NoteCreate} />
|
||||
<Route path="/chat" component={Chat} />
|
||||
@ -112,6 +114,11 @@
|
||||
</a>
|
||||
</li>
|
||||
{/if}
|
||||
<li class="cursor-pointer">
|
||||
<a class="block px-4 py-2 hover:bg-accent transition-all" href="/search">
|
||||
<i class="fa-solid fa-search mr-2" /> Search
|
||||
</a>
|
||||
</li>
|
||||
<li class="cursor-pointer">
|
||||
<a class="block px-4 py-2 hover:bg-accent transition-all" href="/notes">
|
||||
<i class="fa-solid fa-tag mr-2" /> Notes
|
||||
|
@ -1,6 +1,9 @@
|
||||
import './app.css'
|
||||
import App from './App.svelte'
|
||||
|
||||
// Annoying global always fails silently. Figure out an eslint rule instead
|
||||
window.find = null
|
||||
|
||||
const app = new App({
|
||||
target: document.getElementById('app')
|
||||
})
|
||||
|
@ -7,8 +7,8 @@
|
||||
import {hasParent, toHtml} from 'src/util/html'
|
||||
import Anchor from 'src/partials/Anchor.svelte'
|
||||
import {dispatch} from "src/state/dispatch"
|
||||
import {channels, findReplyTo} from "src/state/nostr"
|
||||
import {accounts, modal, annotateNotes} from "src/state/app"
|
||||
import {findReplyTo} from "src/state/nostr"
|
||||
import {accounts, modal} from "src/state/app"
|
||||
import {user} from "src/state/user"
|
||||
import {formatTimestamp} from 'src/util/misc'
|
||||
import UserBadge from "src/partials/UserBadge.svelte"
|
||||
|
@ -1,10 +1,8 @@
|
||||
<script>
|
||||
import {onMount} from 'svelte'
|
||||
import {writable} from 'svelte/store'
|
||||
import {fly} from 'svelte/transition'
|
||||
import {find, propEq} from 'ramda'
|
||||
import Spinner from 'src/partials/Spinner.svelte'
|
||||
import {Cursor, channels} from "src/state/nostr"
|
||||
import {channels} from "src/state/nostr"
|
||||
import {notesListener, annotateNotes, modal} from "src/state/app"
|
||||
import {user} from "src/state/user"
|
||||
import Note from 'src/partials/Note.svelte'
|
||||
|
@ -1,7 +1,6 @@
|
||||
<script>
|
||||
import {onMount, onDestroy} from 'svelte'
|
||||
import {writable} from 'svelte/store'
|
||||
import {fly} from 'svelte/transition'
|
||||
import {navigate} from "svelte-routing"
|
||||
import {uniqBy, prop} from 'ramda'
|
||||
import Anchor from "src/partials/Anchor.svelte"
|
||||
|
118
src/routes/Search.svelte
Normal file
118
src/routes/Search.svelte
Normal file
@ -0,0 +1,118 @@
|
||||
<script>
|
||||
import {onMount, onDestroy} from 'svelte'
|
||||
import {writable} from 'svelte/store'
|
||||
import {fly} from 'svelte/transition'
|
||||
import {uniqBy, uniq, pluck, prop} from 'ramda'
|
||||
import {fuzzy} from "src/util/misc"
|
||||
import Anchor from "src/partials/Anchor.svelte"
|
||||
import Input from "src/partials/Input.svelte"
|
||||
import Spinner from "src/partials/Spinner.svelte"
|
||||
import Note from "src/partials/Note.svelte"
|
||||
import {relays, Cursor} from "src/state/nostr"
|
||||
import {createScroller, accounts, annotateNotes, modal} from "src/state/app"
|
||||
|
||||
const notes = writable([])
|
||||
const people = writable([])
|
||||
let type = writable('people')
|
||||
let q = ''
|
||||
let search
|
||||
let cursor
|
||||
let scroller
|
||||
let modalUnsub
|
||||
|
||||
$: search = (
|
||||
$type === 'people'
|
||||
? fuzzy($people, {keys: ["name", "about"]})
|
||||
: fuzzy($notes, {keys: ["content"]})
|
||||
)
|
||||
|
||||
onMount(async () => {
|
||||
cursor = new Cursor({kinds: [1]})
|
||||
scroller = createScroller(cursor, async chunk => {
|
||||
const annotated = await annotateNotes(chunk)
|
||||
const keys = uniq(pluck('pubkey', chunk))
|
||||
|
||||
notes.update($notes => uniqBy(prop('id'), $notes.concat(annotated)))
|
||||
people.update($people => uniqBy(prop('id'), $people.concat(keys.map(k => $accounts[k]))))
|
||||
})
|
||||
|
||||
// When a modal opens, suspend our subscriptions
|
||||
modalUnsub = modal.subscribe(async $modal => {
|
||||
if ($modal) {
|
||||
cursor.stop()
|
||||
scroller.stop()
|
||||
} else {
|
||||
cursor.start()
|
||||
scroller.start()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
cursor?.stop()
|
||||
scroller?.stop()
|
||||
modalUnsub?.()
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:window on:scroll={scroller?.start} />
|
||||
|
||||
<ul class="border-b border-solid border-dark flex max-w-xl m-auto pt-2" in:fly={{y: 20}}>
|
||||
<li
|
||||
class="px-8 py-4 cursor-pointer hover:border-b border-solid border-medium"
|
||||
class:border-b={$type === 'people'}
|
||||
on:click={() => type.set('people')}>
|
||||
People
|
||||
</li>
|
||||
<li
|
||||
class="px-8 py-4 cursor-pointer hover:border-b border-solid border-medium"
|
||||
class:border-b={$type === 'notes'}
|
||||
on:click={() => type.set('notes')}>
|
||||
Notes
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="max-w-xl m-auto mt-4" in:fly={{y: 20}}>
|
||||
<Input bind:value={q} placeholder="Search for {$type}">
|
||||
<i slot="before" class="fa-solid fa-search" />
|
||||
</Input>
|
||||
</div>
|
||||
|
||||
<ul class="py-8 flex flex-col gap-2 max-w-xl m-auto">
|
||||
{#each search(q) as e (e.id)}
|
||||
<li in:fly={{y: 20}}>
|
||||
{#if e.isAccount}
|
||||
<a href="/users/{e.pubkey}" class="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({e.picture})" />
|
||||
<div class="flex-grow">
|
||||
<h1 class="text-2xl">{e.name}</h1>
|
||||
<p>{e.about || ''}</p>
|
||||
</div>
|
||||
</a>
|
||||
{:else}
|
||||
<Note interactive note={e} />
|
||||
{#each e.replies as r (r.id)}
|
||||
<div class="ml-6 border-l border-solid border-medium">
|
||||
<Note interactive isReply note={r} />
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
<!-- This will always be sitting at the bottom in case infinite scrolling can't keep up -->
|
||||
<Spinner />
|
||||
|
||||
{#if $relays.length === 0}
|
||||
<div class="flex w-full justify-center items-center py-16">
|
||||
<div class="text-center max-w-md">
|
||||
You aren't yet connected to any relays. Please click <Anchor href="/settings/relays"
|
||||
>here</Anchor
|
||||
> to get started.
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -50,6 +50,7 @@ export const ensureAccounts = async (pubkeys, {force = false} = {}) => {
|
||||
...$accounts[e.pubkey],
|
||||
...JSON.parse(e.content),
|
||||
refreshed: now(),
|
||||
isAccount: true,
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {writable, get} from 'svelte/store'
|
||||
import {relayPool, getPublicKey} from 'nostr-tools'
|
||||
import {last, intersection, uniqBy, prop} from 'ramda'
|
||||
import {last, find, intersection, uniqBy, prop} from 'ramda'
|
||||
import {first, noop, ensurePlural} from 'hurdak/lib/hurdak'
|
||||
import {getLocalJson, setLocalJson, now, timedelta} from "src/util/misc"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user