Allow advanced filters to control entire feed

This commit is contained in:
Jonathan Staab 2023-06-13 15:14:31 -07:00
parent 8f96398419
commit 509e316ee6
3 changed files with 62 additions and 64 deletions

View File

@ -27,7 +27,7 @@
export let invertColors = false
export let onEvent = null
let sub, scroller, cursor, overrides
let sub, scroller, cursor
let key = Math.random()
let search = ""
let notes = []
@ -37,7 +37,6 @@
$: searchNotes = debounce(300, fuzzy(notes, {keys: ["content"]}))
$: filteredNotes = search ? searchNotes(search) : notes
$: mergedFilter = mergeFilter(filter, overrides)
const since = now()
const maxNotes = 100
@ -121,14 +120,14 @@
let p = Promise.resolve()
// If we have a search term we need to use only relays that support search
const getRelays = () => (overrides?.search ? [{url: "wss://relay.nostr.band"}] : relays)
const getRelays = () => (filter.search ? [{url: "wss://relay.nostr.band"}] : relays)
const loadMore = async () => {
const _key = key
// Wait for this page to load before trying again
await cursor.loadPage({
filter: mergedFilter,
filter,
onChunk: chunk => {
// Stack promises to avoid too many concurrent subscriptions
p = p.then(() => key === _key && onChunk(chunk))
@ -145,19 +144,19 @@
key = Math.random()
}
const start = (_overrides = {}) => {
if (!equals(_overrides, overrides)) {
const start = (newFilter = {}) => {
if (!equals(newFilter, filter)) {
stop()
const _key = key
overrides = _overrides
filter = {...filter, ...newFilter}
// No point in subscribing if we have an end date
if (!filter.until) {
sub = network.listen({
relays: getRelays(),
filter: mergeFilter(mergedFilter, {since}),
filter: mergeFilter(filter, {since}),
onChunk: chunk => {
p = p.then(() => _key === key && onChunk(chunk))
},
@ -166,7 +165,7 @@
cursor = new network.Cursor({
relays: getRelays(),
until: overrides.until || now(),
until: filter.until || now(),
delta,
})
@ -193,8 +192,8 @@
{/if}
<div class="flex justify-between gap-4" in:fly={{y: 20}}>
<FilterSummary filter={mergedFilter} />
<FeedAdvanced onChange={start} hide={Object.keys(filter)} />
<FilterSummary {filter} />
<FeedAdvanced {filter} onChange={start} />
</div>
<div class="flex flex-col gap-4">

View File

@ -1,6 +1,6 @@
<script lang="ts">
import type {Filter} from "nostr-tools"
import {pluck} from "ramda"
import {pluck, objOf} from "ramda"
import {debounce} from "throttle-debounce"
import {createLocalDate} from "src/util/misc"
import Input from "src/partials/Input.svelte"
@ -11,32 +11,34 @@
import PersonBadge from "src/app/shared/PersonBadge.svelte"
import {searchTopics, searchPeople, getPersonWithFallback} from "src/agent/db"
export let hide = []
export let onChange
export let filter = {} as Filter
let filter = {
since: null,
until: null,
authors: [],
search: "",
"#t": [],
"#p": [],
let _filter = {
since: filter.since,
until: filter.since,
search: filter.search || "",
authors: (filter.authors || []).map(getPersonWithFallback),
"#t": (filter["#t"] || []).map(objOf("name")),
"#p": (filter["#p"] || []).map(getPersonWithFallback),
}
let modal = null
const applyFilter = debounce(300, () => {
if (modal !== "maxi") {
const _filter = {} as Filter
const newFilter = {} as Filter
if (filter.since) _filter.since = createLocalDate(filter.since).setHours(23, 59, 59, 0) / 1000
if (filter.until) _filter.until = createLocalDate(filter.until).setHours(23, 59, 59, 0) / 1000
if (filter.authors.length > 0) _filter.authors = pluck("pubkey", filter.authors)
if (filter.search) _filter.search = filter.search
if (filter["#t"].length > 0) _filter["#t"] = pluck("name", filter["#t"])
if (filter["#p"].length > 0) _filter["#p"] = pluck("pubkey", filter["#p"])
if (_filter.since)
newFilter.since = createLocalDate(_filter.since).setHours(23, 59, 59, 0) / 1000
if (_filter.until)
newFilter.until = createLocalDate(_filter.until).setHours(23, 59, 59, 0) / 1000
if (_filter.authors.length > 0) newFilter.authors = pluck("pubkey", _filter.authors)
if (_filter.search) newFilter.search = _filter.search
if (_filter["#t"].length > 0) newFilter["#t"] = pluck("name", _filter["#t"])
if (_filter["#p"].length > 0) newFilter["#p"] = pluck("pubkey", _filter["#p"])
onChange(_filter)
onChange(newFilter)
}
})
@ -68,7 +70,7 @@
<Content size="lg">
<div class="flex flex-col gap-1">
<strong>Search</strong>
<Input bind:value={filter.search} on:input={applyFilter}>
<Input bind:value={_filter.search} on:input={applyFilter}>
<i slot="before" class="fa fa-search" />
</Input>
</div>
@ -76,49 +78,43 @@
<div class="grid grid-cols-2 gap-2">
<div class="flex flex-col gap-1">
<strong>Since</strong>
<Input type="date" bind:value={filter.since} />
<Input type="date" bind:value={_filter.since} />
</div>
<div class="flex flex-col gap-1">
<strong>Until</strong>
<Input type="date" bind:value={filter.until} />
<Input type="date" bind:value={_filter.until} />
</div>
</div>
{#if !hide.includes("authors")}
<div class="flex flex-col gap-1">
<strong>Authors</strong>
<MultiSelect search={$searchPeople} bind:value={filter.authors}>
<div slot="item" let:item>
<div class="-my-1">
<PersonBadge inert person={getPersonWithFallback(item.pubkey)} />
</div>
<div class="flex flex-col gap-1">
<strong>Authors</strong>
<MultiSelect search={$searchPeople} bind:value={_filter.authors}>
<div slot="item" let:item>
<div class="-my-1">
<PersonBadge inert person={getPersonWithFallback(item.pubkey)} />
</div>
</MultiSelect>
</div>
{/if}
{#if !hide.includes("#t")}
<div class="flex flex-col gap-1">
<strong>Topics</strong>
<MultiSelect search={$searchTopics} bind:value={filter["#t"]}>
<div slot="item" let:item>
<div class="-my-1">
#{item.name}
</div>
</div>
</MultiSelect>
</div>
<div class="flex flex-col gap-1">
<strong>Topics</strong>
<MultiSelect search={$searchTopics} bind:value={_filter["#t"]}>
<div slot="item" let:item>
<div class="-my-1">
#{item.name}
</div>
</MultiSelect>
</div>
{/if}
{#if !hide.includes("#p")}
<div class="flex flex-col gap-1">
<strong>Mentions</strong>
<MultiSelect search={$searchPeople} bind:value={filter["#p"]}>
<div slot="item" let:item>
<div class="-my-1">
<PersonBadge inert person={getPersonWithFallback(item.pubkey)} />
</div>
</div>
</MultiSelect>
</div>
<div class="flex flex-col gap-1">
<strong>Mentions</strong>
<MultiSelect search={$searchPeople} bind:value={_filter["#p"]}>
<div slot="item" let:item>
<div class="-my-1">
<PersonBadge inert person={getPersonWithFallback(item.pubkey)} />
</div>
</MultiSelect>
</div>
{/if}
</div>
</MultiSelect>
</div>
<div class="flex justify-end">
<Anchor type="button-accent" on:click={submit}>Apply Filters</Anchor>
</div>

View File

@ -50,6 +50,9 @@
</script>
<div>
{#if parts.length > 0}
<span class="mr-2 mb-2"> Showing notes: </span>
{/if}
{#each parts as part}
<Chip class="mr-2 mb-2">{part}</Chip>
{/each}