Use new feeds

This commit is contained in:
Jon Staab 2024-04-30 11:27:53 -07:00
parent 1db27a5e11
commit 9f2e59e679
21 changed files with 155 additions and 106 deletions

View File

@ -71,7 +71,7 @@
let subs = []
onMount(async () => {
const {filters} = await feedLoader.compiler.compile(feed)
const [{filters}] = await feedLoader.compiler.compile(feed)
const selections = getFilterSelections(filters)
subs = forcePlatformRelaySelections(selections).map(({relay, filters}) =>

View File

@ -1,7 +1,8 @@
<script lang="ts">
import {onMount} from "svelte"
import {Storage} from "hurdak"
import {prop} from 'ramda'
import {prop} from "ramda"
import type {Filter} from "@welshman/util"
import type {Feed} from "@welshman/feeds"
import {createScroller} from "src/util/misc"
import {fly} from "src/util/transition"
@ -25,7 +26,7 @@
export let onEvent = null
let element
let filters = [{ids: []}]
let filters: Filter[] = [{ids: []}]
let limit = 0
let opts = {
feed,
@ -54,9 +55,14 @@
const update = async opts => {
limit = 0
start(opts)
filters = feedLoader.compiler.canCompile(opts.feed)
? prop('filters', await feedLoader.compiler.compile(opts.feed))
: [{ids: []}]
if (feedLoader.compiler.canCompile(opts.feed)) {
const requests = await feedLoader.compiler.compile(opts.feed)
filters = requests.flatMap(r => r.filters)
} else {
filters = [{ids: []}]
}
}
$: {

View File

@ -4,7 +4,7 @@
import {isNil, clamp} from "@welshman/lib"
import type {DynamicFilter, Feed} from "@welshman/feeds"
import {FeedType, Scope, getSubFeeds} from "@welshman/feeds"
import {slide} from 'src/util/transition'
import {slide} from "src/util/transition"
import {formatTimestampAsDate, getStringWidth} from "src/util/misc"
import Card from "src/partials/Card.svelte"
import Popover from "src/partials/Popover.svelte"
@ -68,7 +68,7 @@
if (text) {
setPart({search: text})
} else {
removeParts(['search'])
removeParts(["search"])
}
}
@ -128,7 +128,7 @@
{:else}
{#await feedLoader.compiler.compile(feed)}
<!-- pass -->
{:then { filters: [filter] }}
{:then [{ filters: [filter] }]}
<Popover
class="inline-block"
placement="bottom-end"
@ -217,7 +217,7 @@
{/if}
</div>
{#if isOpen}
{#if true || isOpen}
<Modal onEscape={closeModal}>
<Subheading class="ml-6">Create a custom Feed</Subheading>
<FeedForm {feed} onCancel={closeModal} onChange={saveFeed} />

View File

@ -16,45 +16,43 @@
import SearchSelect from "src/partials/SearchSelect.svelte"
import FilterField from "src/app/shared/FilterField.svelte"
import DVMField from "src/app/shared/DVMField.svelte"
import FeedFormRelay from "src/app/shared/FeedFormRelay.svelte"
import {searchRelayUrls, searchListAddrs, displayListByAddress, displayRelayUrl} from "src/engine"
export let feed
export let onChange
export let onCancel
const pushCursor = i => {
cursor = [...cursor, i]
const controller = {
pushCursor: i => {
cursor = [...cursor, i]
},
popCursor: i => {
cursor = cursor.slice(0, -1)
},
setAtCursor: (v, p = []) => {
feed = assocPath(cursor.concat(p), v, feed)
},
updateAtCursor: (f, p = []) => {
feed = updatePath(cursor.concat(p), f, feed)
},
addFeed: feedType => controller.setAtCursor([...current, [feedType]]),
removeFeed: i => controller.setAtCursor(current.toSpliced(i, 1)),
}
const popCursor = i => {
cursor = cursor.slice(0, -1)
}
const setAtCursor = (v, p = []) => {
feed = assocPath(cursor.concat(p), v, feed)
}
const updateAtCursor = (f, p = []) => {
feed = updatePath(cursor.concat(p), f, feed)
}
const addFeed = feedType => setAtCursor([...current, [feedType]])
const removeFeed = i => setAtCursor(current.toSpliced(i, 1))
const onTypeChange = type => {
if (hasSubFeeds([type])) {
if (hasSubFeeds(current)) {
setAtCursor([type, ...current.slice(1)])
controller.setAtCursor([type, ...current.slice(1)])
} else {
setAtCursor([type, current])
controller.setAtCursor([type, current])
}
} else if (type === FeedType.Filter) {
setAtCursor([type, {}])
controller.setAtCursor([type, {}])
} else if (type === FeedType.DVM) {
setAtCursor([type, {kind: 5300, tags: [], relays: []}])
controller.setAtCursor([type, {kind: 5300, tags: [], relays: []}])
} else {
setAtCursor([type])
controller.setAtCursor([type])
}
}
@ -88,50 +86,52 @@
value={feedType}>
<div slot="item" class="flex flex-col items-center" let:option let:active>
{#if option === FeedType.Filter}
<Icon icon="people-nearby" class="w-12 h-12" color={active ? "accent" : "tinted-800"} />
<span class="text-2xl staatliches">Standard</span>
<Icon icon="people-nearby" class="h-12 w-12" color={active ? "accent" : "tinted-800"} />
<span class="staatliches text-2xl">Standard</span>
{:else if option === FeedType.Relay}
<Icon icon="server" class="w-12 h-12" color={active ? "accent" : "tinted-800"} />
<span class="text-2xl staatliches">Relays</span>
<Icon icon="server" class="h-12 w-12" color={active ? "accent" : "tinted-800"} />
<span class="staatliches text-2xl">Relays</span>
{:else if option === FeedType.DVM}
<Icon icon="network" class="w-12 h-12" color={active ? "accent" : "tinted-800"} />
<span class="text-2xl staatliches">DVMs</span>
<Icon icon="network" class="h-12 w-12" color={active ? "accent" : "tinted-800"} />
<span class="staatliches text-2xl">DVMs</span>
{:else}
<span class="w-12 h-12 flex items-center justify-center">
<span class="flex h-12 w-12 items-center justify-center">
<i class="fa fa-2xl fa-gears" />
</span>
<span class="text-2xl staatliches">Advanced</span>
<span class="staatliches text-2xl">Advanced</span>
{/if}
</div>
</SelectTiles>
</Field>
</Card>
{#if feedType === FeedType.Relay}
<Field label="Relay Selections">
<FeedFormRelay feed={current} {controller} />
<Field label="Which relays would you like to use?">
<SearchSelect
multiple
value={current[1] || []}
search={$searchRelayUrls}
onChange={urls => setAtCursor(urls, [1])}>
onChange={urls => controller.setAtCursor(urls, [1])}>
<span slot="item" let:item>{displayRelayUrl(item)}</span>
</SearchSelect>
<p slot="info">Select which relays you'd like to limit loading feeds from.</p>
</Field>
{:else if feedType === FeedType.Filter}
<FeedFormForRelayFeed feed={current} {controller} />
{#each current.slice(1) as filter, filterIdx ([current.length, filterIdx].join(":"))}
{@const feedIdx = inc(filterIdx)}
<Card>
<FilterField
{filter}
onChange={filter => setAtCursor(filter, [feedIdx])}
onRemove={() => updateAtCursor(feed => feed.toSpliced(feedIdx, 1))} />
onChange={filter => controller.setAtCursor(filter, [feedIdx])}
onRemove={() => controller.updateAtCursor(feed => feed.toSpliced(feedIdx, 1))} />
</Card>
{#if feedIdx < current.length - 1}
<p class="staatliches text-center">— OR —</p>
{/if}
{/each}
<div class="flex">
<Anchor button on:click={() => setAtCursor([...current, {}])}>
<Anchor button on:click={() => controller.setAtCursor([...current, {}])}>
<i class="fa fa-plus" /> Add filter
</Anchor>
</div>
@ -141,7 +141,7 @@
multiple
value={current.slice(1)}
search={$searchListAddrs}
onChange={addrs => setAtCursor([FeedType.List, ...addrs])}>
onChange={addrs => controller.setAtCursor([FeedType.List, ...addrs])}>
<span slot="item" let:item>{displayListByAddress(item)}</span>
</SearchSelect>
<p slot="info">Select which lists you'd like to view.</p>
@ -152,15 +152,17 @@
<Card>
<DVMField
dvmItem={item}
onChange={item => setAtCursor(item, [feedIdx])}
onRemove={() => updateAtCursor(feed => feed.toSpliced(feedIdx, 1))} />
onChange={item => controller.setAtCursor(item, [feedIdx])}
onRemove={() => controller.updateAtCursor(feed => feed.toSpliced(feedIdx, 1))} />
</Card>
{#if feedIdx < current.length - 1}
<p class="staatliches text-center">— OR —</p>
{/if}
{/each}
<div class="flex">
<Anchor button on:click={() => setAtCursor([...current, {kind: 5300, tags: [], relays: []}])}>
<Anchor
button
on:click={() => controller.setAtCursor([...current, {kind: 5300, tags: [], relays: []}])}>
<i class="fa fa-plus" /> Add DVM
</Anchor>
</div>
@ -168,12 +170,14 @@
{#each subFeeds as subFeed, i (displayFeed(subFeed) + i)}
<Card class="flex items-center justify-between">
<div class="flex items-center gap-3">
<Anchor on:click={() => removeFeed(current.indexOf(subFeed))}>
<Anchor on:click={() => controller.removeFeed(current.indexOf(subFeed))}>
<i class="fa fa-trash fa-sm" />
</Anchor>
<span class="text-lg">{displayFeed(subFeed)}</span>
</div>
<Anchor class="flex items-center gap-2" on:click={() => pushCursor(current.indexOf(subFeed))}>
<Anchor
class="flex items-center gap-2"
on:click={() => controller.pushCursor(current.indexOf(subFeed))}>
<i class="fa fa-edit" /> Edit
</Anchor>
</Card>
@ -199,9 +203,9 @@
</div>
<div slot="tooltip">
<Menu>
<MenuItem on:click={() => addFeed(FeedType.Filter)}>Standard Feed</MenuItem>
<MenuItem on:click={() => addFeed(FeedType.List)}>List Feed</MenuItem>
<MenuItem on:click={() => addFeed(FeedType.DVM)}>DVM Feed</MenuItem>
<MenuItem on:click={() => controller.addFeed(FeedType.Filter)}>Standard Feed</MenuItem>
<MenuItem on:click={() => controller.addFeed(FeedType.List)}>List Feed</MenuItem>
<MenuItem on:click={() => controller.addFeed(FeedType.DVM)}>DVM Feed</MenuItem>
</Menu>
</div>
</Popover>
@ -212,7 +216,7 @@
<Anchor button on:click={onCancel}>Cancel</Anchor>
<Anchor button accent on:click={() => onChange(feed)}>Save</Anchor>
{:else}
<Anchor button on:click={popCursor}>Done</Anchor>
<Anchor button on:click={controller.popCursor}>Done</Anchor>
{/if}
</div>
</FlexColumn>

View File

@ -0,0 +1,20 @@
<script lang="ts">
import {FeedType} from "@welshman/feeds"
import Field from "src/partials/Field.svelte"
import SearchSelect from "src/partials/SearchSelect.svelte"
import {searchRelayUrls, displayRelayUrl} from "src/engine"
export let feed
export let controller
</script>
<Field label="Which relays would you like to use?">
<SearchSelect
multiple
value={feed.slice(1)}
search={$searchRelayUrls}
onChange={urls => controller.setAtCursor([FeedType.Relay, ...urls])}>
<span slot="item" let:item>{displayRelayUrl(item)}</span>
</SearchSelect>
<p slot="info">Select which relays you'd like to limit loading feeds from.</p>
</Field>

View File

@ -1,8 +1,8 @@
<script lang="ts">
import {filterFeed} from "@welshman/feeds"
import {feedFromFilter} from "@welshman/feeds"
import Calendar from "src/app/shared/Calendar.svelte"
export let address
</script>
<Calendar group={address} feed={filterFeed({kinds: [31923], "#a": [address]})} />
<Calendar group={address} feed={feedFromFilter({kinds: [31923], "#a": [address]})} />

View File

@ -1,5 +1,5 @@
<script lang="ts">
import {filterFeed} from "@welshman/feeds"
import {feedFromFilter} from "@welshman/feeds"
import Card from "src/partials/Card.svelte"
import Anchor from "src/partials/Anchor.svelte"
import Feed from "src/app/shared/Feed.svelte"
@ -15,4 +15,4 @@
<Anchor button accent on:click={createListing}>Create a listing</Anchor>
</Card>
<Feed hideControls feed={filterFeed({kinds: [30402], "#a": [address]})} />
<Feed hideControls feed={feedFromFilter({kinds: [30402], "#a": [address]})} />

View File

@ -1,7 +1,7 @@
<script lang="ts">
import {without, last} from "ramda"
import {Tag, Tags, decodeAddress, isGroupAddress, getIdFilters} from "@welshman/util"
import {filterFeed} from "@welshman/feeds"
import {feedFromFilter} from "@welshman/feeds"
import {noteKinds, generatePrivateKey} from "src/util/nostr"
import {fly} from "src/util/transition"
import FlexColumn from "src/partials/FlexColumn.svelte"
@ -100,7 +100,7 @@
shouldListen
hideControls
skipNetwork={isGroupAddress(decodeAddress(address))}
feed={filterFeed({kinds: without([30402], noteKinds), "#a": [address]})} />
feed={feedFromFilter({kinds: without([30402], noteKinds), "#a": [address]})} />
{:else}
{#each feedEvents as event}
<div in:fly={{y: 20}}>

View File

@ -218,7 +218,7 @@
"pointer-events-none opacity-50": disableActions,
})}
on:click={replyCtrl?.start}>
<Icon icon="message" accent={reply ? 'accent' : 'neutral-100'} />
<Icon icon="message" color={reply ? 'accent' : 'neutral-100'} />
{#if $repliesCount > 0}
<span transition:fly|local={{y: 5, duration: 100}} class="-mt-px">{$repliesCount}</span>
{/if}
@ -229,7 +229,7 @@
"pointer-events-none opacity-50": disableActions || !canZap,
})}
on:click={startZap}>
<Icon icon="bolt" accent={zap ? 'accent' : 'neutral-100'} />
<Icon icon="bolt" color={zap ? 'accent' : 'neutral-100'} />
{#if $zapsTotal > 0}
<span transition:fly|local={{y: 5, duration: 100}} class="-mt-px"
>{formatSats($zapsTotal)}</span>
@ -244,7 +244,7 @@
on:click={() => (like ? deleteReaction(like) : react("+"))}>
<Icon
icon="heart"
accent={Boolean(like)}
color={like ? 'accent' : 'neutral-100'}
class={cx("cursor-pointer", {
"fa-beat fa-beat-custom": like,
})} />

View File

@ -56,6 +56,7 @@ export class FeedLoader {
isDeleted = isDeleted.get()
constructor(readonly opts: FeedOpts) {
// @ts-ignore
window.feed = this
// Use a custom feed loader so we can intercept the filters
@ -63,7 +64,7 @@ export class FeedLoader {
...baseFeedLoader.options,
request: async ({relays, filters, onEvent}) => {
// Default to note kinds
filters = filters.map(filter => ({kinds: noteKinds, ...filter}))
filters = filters?.map(filter => ({kinds: noteKinds, ...filter})) || []
// Add reposts if we don't have any authors specified
if (this.opts.includeReposts && !filters.some(f => f.authors?.length > 0)) {
@ -74,7 +75,7 @@ export class FeedLoader {
const tracker = new Tracker()
// Use relays specified in feeds
if (relays.length > 0) {
if (relays?.length > 0) {
promises.push(load({filters, relays, tracker, onEvent}))
} else {
if (!this.opts.skipCache) {
@ -132,12 +133,12 @@ export class FeedLoader {
// Event selection, deferral, and parent loading
discardEvents = async events => {
let strict = false
let strict = true
// Be more tolerant when looking at communities
this.feedLoader.compiler.walk(this.opts.feed, ([type, ...feed]) => {
if (type === FeedType.Filter) {
strict = feed.some(f => f["#a"]?.find(a => isContextAddress(decodeAddress(a))))
this.feedLoader.compiler.walk(this.opts.feed, ([type, key, ...feed]) => {
if (type === FeedType.Tag && key === "#a") {
strict = strict && !feed.some(a => isContextAddress(decodeAddress(a)))
}
})

View File

@ -1,11 +1,11 @@
<script lang="ts">
import {Scope, filterFeed} from "@welshman/feeds"
import {Scope, feedFromFilter, intersectionFeed, kindFeed, scopeFeed} from "@welshman/feeds"
import Calendar from "src/app/shared/Calendar.svelte"
import {env, loadGroupMessages} from "src/engine"
const feed = $env.FORCE_GROUP
? filterFeed({kinds: [31923], "#a": [$env.FORCE_GROUP]})
: filterFeed({kinds: [31923], scopes: [Scope.Self, Scope.Follows]})
? feedFromFilter({kinds: [31923], "#a": [$env.FORCE_GROUP]})
: intersectionFeed(kindFeed(31923), scopeFeed(Scope.Self, Scope.Follows))
if ($env.FORCE_GROUP) {
loadGroupMessages([$env.FORCE_GROUP])

View File

@ -1,7 +1,7 @@
<script lang="ts">
import {onMount} from "svelte"
import {getIdOrAddress, decodeAddress} from "@welshman/util"
import {filterFeed} from "@welshman/feeds"
import {feedFromFilter} from "@welshman/feeds"
import {fly} from "src/util/transition"
import FlexColumn from "src/partials/FlexColumn.svelte"
import Spinner from "src/partials/Spinner.svelte"
@ -38,7 +38,7 @@
hideControls
shouldListen
anchor={getIdOrAddress(event)}
feed={filterFeed({"#a": [address]})} />
feed={feedFromFilter({"#a": [address]})} />
</FlexColumn>
</div>
{:else}

View File

@ -1,7 +1,8 @@
<script lang="ts">
import cx from "classnames"
import {Tags} from "@welshman/util"
import {Scope, filterFeed, relayFeed} from "@welshman/feeds"
import {Scope, authorFeed, tagFeed, scopeFeed, relayFeed, intersectionFeed} from "@welshman/feeds"
import type {Feed as TFeed} from "@welshman/feeds"
import {theme} from "src/partials/state"
import Anchor from "src/partials/Anchor.svelte"
import Popover from "src/partials/Popover.svelte"
@ -10,10 +11,10 @@
import {session, canSign, lists, userLists} from "src/engine"
export let relays = []
export let feed = filterFeed({scopes: [Scope.Follows]})
export let feed: TFeed = scopeFeed(Scope.Follows)
if (relays.length > 0) {
feed = relayFeed(relays, feed)
feed = intersectionFeed(relayFeed(...relays), feed)
}
let key = Math.random()
@ -30,15 +31,15 @@
const urls = tags.values("r").valueOf()
if (authors.length > 0) {
feed = filterFeed({authors})
feed = authorFeed(...authors)
} else if (topics.length > 0) {
feed = filterFeed({"#t": topics})
feed = tagFeed("#t", ...topics)
} else {
feed = filterFeed({scopes: [Scope.Follows]})
feed = scopeFeed(Scope.Follows)
}
if (urls.length > 0) {
feed = relayFeed(urls, feed)
feed = intersectionFeed(relayFeed(...urls), feed)
}
key = Math.random()

View File

@ -1,5 +1,5 @@
<script lang="ts">
import {Scope, filterFeed} from "@welshman/feeds"
import {Scope, feedFromFilter, intersectionFeed, kindFeed, scopeFeed} from "@welshman/feeds"
import Card from "src/partials/Card.svelte"
import Anchor from "src/partials/Anchor.svelte"
import Feed from "src/app/shared/Feed.svelte"
@ -7,8 +7,8 @@
import {env, canSign, loadGroupMessages} from "src/engine"
const feed = $env.FORCE_GROUP
? filterFeed({kinds: [30402], "#a": [$env.FORCE_GROUP]})
: filterFeed({kinds: [30402], scopes: [Scope.Self, Scope.Follows]})
? feedFromFilter({kinds: [30402], "#a": [$env.FORCE_GROUP]})
: intersectionFeed(kindFeed(30402), scopeFeed(Scope.Self, Scope.Follows))
const createListing = () => router.at("notes/create").qp({type: "listing"}).open()

View File

@ -1,7 +1,7 @@
<script lang="ts">
import {identity} from "ramda"
import {stripProtocol} from "@welshman/lib"
import {filterFeed} from "@welshman/feeds"
import {feedFromFilter} from "@welshman/feeds"
import {info} from "src/util/logger"
import {ensureProto} from "src/util/misc"
import {themeBackgroundGradient} from "src/partials/state"
@ -30,7 +30,7 @@
export let npub
export let pubkey
export let relays = []
export let feed = filterFeed({authors: [pubkey]})
export let feed = feedFromFilter({authors: [pubkey]})
const tabs = ["notes", "likes", "collections", "relays"].filter(identity)
const person = derivePerson(pubkey)
@ -98,7 +98,7 @@
{:else if activeTab === "notes"}
<Feed showGroup skipPlatform {feed} />
{:else if activeTab === "likes"}
<Feed showGroup hideControls feed={filterFeed({kinds: [7], authors: [pubkey]})} />
<Feed showGroup hideControls feed={feedFromFilter({kinds: [7], authors: [pubkey]})} />
{:else if activeTab === "collections"}
<PersonCollections {pubkey} />
{:else if activeTab === "relays"}

View File

@ -1,6 +1,7 @@
<script lang="ts">
import {batch} from "hurdak"
import {filterFeed, relayFeed} from "@welshman/feeds"
import {wotFeed, relayFeed, intersectionFeed, feedFromFilter} from "@welshman/feeds"
import type {Feed as TFeed} from "@welshman/feeds"
import {getAvgRating} from "src/util/nostr"
import Feed from "src/app/shared/Feed.svelte"
import Tabs from "src/partials/Tabs.svelte"
@ -10,13 +11,13 @@
import {deriveRelay, normalizeRelayUrl, displayRelay, getMinWot} from "src/engine"
export let url
export let feed = filterFeed({min_wot: getMinWot()})
export let feed: TFeed = wotFeed({min: getMinWot()})
let reviews = []
let activeTab = "notes"
$: url = normalizeRelayUrl(url)
$: feed = relayFeed([url], feed)
$: feed = intersectionFeed(relayFeed(url), feed)
$: rating = getAvgRating(reviews)
const relay = deriveRelay(url)
@ -48,7 +49,7 @@
{#if activeTab === "reviews"}
<Feed
onEvent={onReview}
feed={filterFeed({
feed={feedFromFilter({
kinds: [1986],
"#l": ["review/relay"],
"#r": [$relay.url],

View File

@ -1,5 +1,5 @@
<script lang="ts">
import {filterFeed} from "@welshman/feeds"
import {tagFeed} from "@welshman/feeds"
import Feed from "src/app/shared/Feed.svelte"
import Heading from "src/partials/Heading.svelte"
import TopicActions from "src/app/shared/TopicActions.svelte"
@ -13,4 +13,4 @@
<TopicActions {topic} />
</div>
</div>
<Feed feed={filterFeed({"#t": [topic]})} />
<Feed feed={tagFeed("#t", topic)} />

View File

@ -1,7 +1,7 @@
import {assocPath, uniq} from "ramda"
import {seconds} from "hurdak"
import {now} from "@welshman/lib"
import {relayFeed, filterFeed} from "@welshman/feeds"
import {relayFeed, feedFromFilter, unionFeed, intersectionFeed} from "@welshman/feeds"
import {sessions} from "src/engine/session/state"
import {session} from "src/engine/session/derived"
import {loadPubkeys, subscribe} from "src/engine/network/utils"
@ -21,9 +21,12 @@ export const loadAllMessages = ({reload = false} = {}) => {
})
const loader = loadAll(
relayFeed(
hints.User().getUrls(),
filterFeed({kinds: [4], authors: [pubkey], since}, {kinds: [4, 1059], "#p": [pubkey], since}),
intersectionFeed(
relayFeed(...hints.User().getUrls()),
unionFeed(
feedFromFilter({kinds: [4], authors: [pubkey], since}),
feedFromFilter({kinds: [4, 1059], "#p": [pubkey], since}),
),
),
)

View File

@ -2,7 +2,14 @@ import {seconds, switcherFn} from "hurdak"
import {Worker, writable} from "@welshman/lib"
import type {Event, Rumor} from "@welshman/util"
import type {LoadOpts} from "@welshman/feeds"
import {FeedLoader, Scope, relayFeed, filterFeed} from "@welshman/feeds"
import {
FeedLoader,
Scope,
relayFeed,
intersectionFeed,
unionFeed,
feedFromFilter,
} from "@welshman/feeds"
import {giftWrapKinds, generatePrivateKey} from "src/util/nostr"
import {env} from "src/engine/session/state"
import {user, session, nip44, nip04} from "src/engine/session/derived"
@ -136,7 +143,9 @@ export const sync = (fromUrl, toUrl, filters) => {
worker.addGlobalHandler(event => publish({event, relays: [toUrl]}))
return loadAll(relayFeed([fromUrl], filterFeed(...filters)), {
const feed = intersectionFeed(relayFeed(fromUrl), unionFeed(...filters.map(feedFromFilter)))
return loadAll(feed, {
onEvent: e => worker.push(e as Event),
})
}

View File

@ -1,9 +1,9 @@
<script lang="ts">
import cx from "classnames"
import {without} from 'ramda'
import {without} from "ramda"
export let options
export let value
export let value = null
export let options = []
export let onChange = null
export let disabled = false
export let multiple = false
@ -26,7 +26,11 @@
class:cursor-pointer={!disabled}>
{#each options as option, i}
<div on:click={() => onClick(option)}>
<slot name="item" {i} {option} active={multiple ? value.includes(option) : value === option} />
<slot
name="item"
{i}
{option}
active={multiple ? value.includes(option) : value === option} />
</div>
{/each}
</div>

View File

@ -325,7 +325,7 @@ export const pickVals = <T>(ks: string[], x: Record<string, T>) => ks.map(k => x
export const getStringWidth = (text: string) => {
const span = document.createElement("span")
span.style = "height: 0px"
span.setAttribute("style", "height: 0px")
span.textContent = text
document.body.appendChild(span)