diff --git a/src/app/shared/FeedCard.svelte b/src/app/shared/FeedCard.svelte index 73db82ad..cb95e534 100644 --- a/src/app/shared/FeedCard.svelte +++ b/src/app/shared/FeedCard.svelte @@ -1,5 +1,6 @@ @@ -70,6 +77,12 @@ {#if feed.description}

{feed.description}

{/if} + {#if favoritedPubkeys.length > 0} +
+ Bookmarked by + +
+ {/if}
diff --git a/src/app/views/FeedList.svelte b/src/app/views/FeedList.svelte index 531957eb..f2bc8993 100644 --- a/src/app/views/FeedList.svelte +++ b/src/app/views/FeedList.svelte @@ -1,8 +1,10 @@ @@ -96,7 +121,7 @@ {#each $feedSearch .searchValues(q) - .filter(address => !feeds.find(feed => getAddress(feed.event) === address)) + .filter(address => !initialAddrs.has(address)) .slice(0, limit) as address (address)} {/each} diff --git a/src/domain/feed.ts b/src/domain/feed.ts index fdde5e95..e5ed2e6b 100644 --- a/src/domain/feed.ts +++ b/src/domain/feed.ts @@ -1,5 +1,5 @@ import {fromPairs, randomId} from "@welshman/lib" -import {FEED, Tags, getAddress} from "@welshman/util" +import {FEED, Tags} from "@welshman/util" import type {TrustedEvent} from "@welshman/util" import { feedFromTags, @@ -10,7 +10,6 @@ import { isScopeFeed, } from "@welshman/feeds" import type {Feed as IFeed} from "@welshman/feeds" -import {SearchHelper} from "src/util/misc" import {tryJson} from "src/util/misc" import type {PublishedList} from "./list" @@ -81,12 +80,6 @@ export const editFeed = (feed: PublishedFeed) => ({ export const displayFeed = (feed?: Feed) => feed?.title || "[no name]" -export class FeedSearch extends SearchHelper { - config = {keys: ["title", "description"]} - getValue = (option: PublishedFeed) => getAddress(option.event) - displayValue = (address: string) => displayFeed(this.getOption(address)) -} - export const isTopicFeed = f => isTagFeed(f) && f[1] === "#t" export const isMentionFeed = f => isTagFeed(f) && f[1] === "#p" diff --git a/src/engine/requests/pubkeys.ts b/src/engine/requests/pubkeys.ts index 235c76c4..600d8266 100644 --- a/src/engine/requests/pubkeys.ts +++ b/src/engine/requests/pubkeys.ts @@ -50,7 +50,7 @@ const getFiltersForKey = (key: string, authors: string[]) => { case "pubkey/lists": return [{authors, kinds: LIST_KINDS}] case "pubkey/feeds": - return [{authors, kinds: [NAMED_BOOKMARKS, FEED]}] + return [{authors, kinds: [NAMED_BOOKMARKS, FEED, FEEDS]}] case "pubkey/relays": return [{authors, kinds: [RELAYS, INBOX_RELAYS]}] case "pubkey/profile": diff --git a/src/engine/state.ts b/src/engine/state.ts index bef8e546..c997d823 100644 --- a/src/engine/state.ts +++ b/src/engine/state.ts @@ -116,11 +116,11 @@ import type { } from "src/domain" import { RelayMode, + displayFeed, EDITABLE_LIST_KINDS, getSingletonValues, makeSingleton, ListSearch, - FeedSearch, profileHasName, readFeed, readList, @@ -1350,6 +1350,20 @@ export const feedFavorites = deriveEventsMapped({ ), }) +export const feedFavoritesByAddress = withGetter( + derived(feedFavorites, $feedFavorites => { + const $feedFavoritesByAddress = new Map() + + for (const singleton of $feedFavorites) { + for (const address of getSingletonValues("a", singleton)) { + pushToMapKey($feedFavoritesByAddress, address, singleton) + } + } + + return $feedFavoritesByAddress + }), +) + export const userFeedFavorites = derived( [feedFavorites, pubkey], ([$singletons, $pubkey]: [PublishedSingleton[], string]) => @@ -1363,6 +1377,35 @@ export const userFavoritedFeeds = derived(userFeedFavorites, $singleton => .map(readFeed), ) +export class FeedSearch extends SearchHelper { + getSearch = () => { + const $feedFavoritesByAddress = feedFavoritesByAddress.get() + const getScore = feed => $feedFavoritesByAddress.get(getAddress(feed.event))?.length || 0 + const options = this.options.map(feed => ({feed, score: getScore(feed)})) + const fuse = new Fuse(options, { + keys: ["feed.title", "feed.description"], + shouldSort: false, + includeScore: true, + }) + + return (term: string) => { + if (!term) { + return sortBy(item => -item.score, options).map(item => item.feed) + } + + return doPipe(fuse.search(term), [ + results => + sortBy((r: any) => r.score - Math.pow(Math.max(0, r.item.score), 1 / 100), results), + results => results.map((r: any) => r.item.feed), + ]) + } + } + + getValue = (option: PublishedFeed) => getAddress(option.event) + + displayValue = (address: string) => displayFeed(this.getOption(address)) +} + export const feedSearch = derived(feeds, $feeds => new FeedSearch($feeds)) export const listFeeds = deriveEventsMapped({