forked from coracle/flotilla
Simplify and optimize notifications
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import {onMount} from "svelte"
|
||||
import {page} from "$app/stores"
|
||||
import {remove, assoc} from "@welshman/lib"
|
||||
import {remove} from "@welshman/lib"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {pubkey, loadInboxRelaySelections} from "@welshman/app"
|
||||
import {fade} from "@lib/transition"
|
||||
@@ -10,7 +10,7 @@
|
||||
import ProfileCircle from "@app/components/ProfileCircle.svelte"
|
||||
import ProfileCircles from "@app/components/ProfileCircles.svelte"
|
||||
import {makeChatPath} from "@app/routes"
|
||||
import {CHAT_FILTERS, deriveNotification} from "@app/notifications"
|
||||
import {notifications} from "@app/notifications"
|
||||
|
||||
export let id: string
|
||||
export let pubkeys: string[]
|
||||
@@ -19,7 +19,6 @@
|
||||
const others = remove($pubkey!, pubkeys)
|
||||
const active = $page.params.chat === id
|
||||
const path = makeChatPath(pubkeys)
|
||||
const notification = deriveNotification(path, CHAT_FILTERS.map(assoc("authors", pubkeys)))
|
||||
|
||||
onMount(() => {
|
||||
for (const pk of others) {
|
||||
@@ -47,7 +46,7 @@
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
{#if !active && $notification}
|
||||
{#if !active && $notifications.has(path)}
|
||||
<div class="h-2 w-2 rounded-full bg-primary" transition:fade />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
deriveUserRooms,
|
||||
deriveOtherRooms,
|
||||
} from "@app/state"
|
||||
import {deriveNotification, THREAD_FILTERS} from "@app/notifications"
|
||||
import {notifications} from "@app/notifications"
|
||||
import {pullConservatively} from "@app/requests"
|
||||
import {pushModal} from "@app/modal"
|
||||
import {makeSpacePath} from "@app/routes"
|
||||
@@ -30,7 +30,6 @@
|
||||
export let url
|
||||
|
||||
const threadsPath = makeSpacePath(url, "threads")
|
||||
const threadsNotification = deriveNotification(threadsPath, THREAD_FILTERS, url)
|
||||
const userRooms = deriveUserRooms(url)
|
||||
const otherRooms = deriveOtherRooms(url)
|
||||
|
||||
@@ -114,7 +113,7 @@
|
||||
<SecondaryNavItem href={makeSpacePath(url)}>
|
||||
<Icon icon="home-smile" /> Home
|
||||
</SecondaryNavItem>
|
||||
<SecondaryNavItem href={threadsPath} notification={$threadsNotification}>
|
||||
<SecondaryNavItem href={threadsPath} notification={$notifications.has(threadsPath)}>
|
||||
<Icon icon="notes-minimalistic" /> Threads
|
||||
</SecondaryNavItem>
|
||||
<div class="h-2" />
|
||||
|
||||
@@ -1,48 +1,21 @@
|
||||
<script lang="ts">
|
||||
import {page} from "$app/stores"
|
||||
import {derived} from "svelte/store"
|
||||
import {max} from "@welshman/lib"
|
||||
import {matchFilter, MESSAGE} from "@welshman/util"
|
||||
import {pubkey} from "@welshman/app"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import MenuSpace from "@app/components/MenuSpace.svelte"
|
||||
import {checked, getNotification, deriveNotification, THREAD_FILTERS} from "@app/notifications"
|
||||
import {userMembership, getMembershipRoomsByUrl, deriveEventsForUrl, GENERAL} from "@app/state"
|
||||
import {makeRoomPath, makeSpacePath} from "@app/routes"
|
||||
import {notifications} from "@app/notifications"
|
||||
import {makeSpacePath} from "@app/routes"
|
||||
import {pushDrawer} from "@app/modal"
|
||||
|
||||
export let url
|
||||
|
||||
const path = makeSpacePath(url)
|
||||
|
||||
const openMenu = () => pushDrawer(MenuSpace, {url})
|
||||
|
||||
const events = deriveEventsForUrl(url, [{kinds: [MESSAGE]}])
|
||||
|
||||
const threadsPath = makeSpacePath(url, "threads")
|
||||
|
||||
const threadsNotification = deriveNotification(threadsPath, THREAD_FILTERS, url)
|
||||
|
||||
const notification = derived(
|
||||
[page, events, checked, userMembership],
|
||||
([$page, $events, $checked, $userMembership]) =>
|
||||
getMembershipRoomsByUrl(url, $userMembership)
|
||||
.concat(GENERAL)
|
||||
.some(room => {
|
||||
const path = makeRoomPath(url, room)
|
||||
|
||||
if ($page.url.pathname === path) return false
|
||||
|
||||
const lastChecked = max([$checked["*"], $checked[path]])
|
||||
const roomEvents = $events.filter(e => matchFilter({"#h": [room]}, e))
|
||||
|
||||
return getNotification($pubkey, lastChecked, roomEvents)
|
||||
}),
|
||||
)
|
||||
</script>
|
||||
|
||||
<Button on:click={openMenu} class="btn btn-neutral btn-sm relative md:hidden">
|
||||
<Icon icon="menu-dots" />
|
||||
{#if $threadsNotification || $notification}
|
||||
{#if $notifications.has(path)}
|
||||
<div class="absolute right-0 top-0 -mr-1 -mt-1 h-2 w-2 rounded-full bg-primary" />
|
||||
{/if}
|
||||
</Button>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<script lang="ts">
|
||||
import {readable} from "svelte/store"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
|
||||
import ChannelName from "@app/components/ChannelName.svelte"
|
||||
import {makeSpacePath} from "@app/routes"
|
||||
import {deriveChannel, channelIsLocked} from "@app/state"
|
||||
import {deriveNotification, getRoomFilters} from "@app/notifications"
|
||||
import {notifications} from "@app/notifications"
|
||||
|
||||
export let url
|
||||
export let room
|
||||
@@ -13,12 +12,9 @@
|
||||
|
||||
const path = makeSpacePath(url, room)
|
||||
const channel = deriveChannel(url, room)
|
||||
const notification = notify
|
||||
? deriveNotification(path, getRoomFilters(room), url)
|
||||
: readable(false)
|
||||
</script>
|
||||
|
||||
<SecondaryNavItem href={path} notification={$notification}>
|
||||
<SecondaryNavItem href={path} notification={notify ? $notifications.has(path) : false}>
|
||||
{#if channelIsLocked($channel)}
|
||||
<Icon icon="lock" size={4} />
|
||||
{:else}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import RelayName from "@app/components/RelayName.svelte"
|
||||
import RelayDescription from "@app/components/RelayDescription.svelte"
|
||||
import {makeSpacePath} from "@app/routes"
|
||||
import {inactiveSpacesNotifications} from "@app/notifications"
|
||||
import {inactiveNotifications} from "@app/notifications"
|
||||
|
||||
export let url
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<div slot="icon"><SpaceAvatar {url} /></div>
|
||||
<div slot="title" class="flex gap-1">
|
||||
<RelayName {url} />
|
||||
{#if $inactiveSpacesNotifications.includes(path)}
|
||||
{#if $inactiveNotifications.has(path)}
|
||||
<div class="relative top-1 h-2 w-2 rounded-full bg-primary" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -17,20 +17,22 @@
|
||||
PLATFORM_LOGO,
|
||||
} from "@app/state"
|
||||
import {pushModal} from "@app/modal"
|
||||
import {deriveNotification, inactiveSpacesNotifications, CHAT_FILTERS} from "@app/notifications"
|
||||
|
||||
const chatNotification = deriveNotification("/chat", CHAT_FILTERS)
|
||||
import {makeSpacePath} from "@app/routes"
|
||||
import {notifications, inactiveNotifications} from "@app/notifications"
|
||||
|
||||
const addSpace = () => pushModal(SpaceAdd)
|
||||
|
||||
const showSpacesMenu = () =>
|
||||
getMembershipUrls($userMembership).length > 0 ? pushModal(MenuSpaces) : pushModal(SpaceAdd)
|
||||
const showSpacesMenu = () => (spacePaths.length > 0 ? pushModal(MenuSpaces) : pushModal(SpaceAdd))
|
||||
|
||||
const showSettingsMenu = () => pushModal(MenuSettings)
|
||||
|
||||
const openNotes = () => ($canDecrypt ? goto("/notes") : pushModal(ChatEnable, {next: "/notes"}))
|
||||
|
||||
const openChat = () => ($canDecrypt ? goto("/chat") : pushModal(ChatEnable, {next: "/chat"}))
|
||||
|
||||
$: spaceUrls = getMembershipUrls($userMembership)
|
||||
$: spacePaths = spaceUrls.map(url => makeSpacePath(url))
|
||||
$: anySpaceNotifications = spacePaths.some(path => $inactiveNotifications.has(path))
|
||||
</script>
|
||||
|
||||
<div class="relative z-nav hidden w-14 flex-shrink-0 bg-base-200 pt-4 md:block">
|
||||
@@ -43,7 +45,7 @@
|
||||
<Avatar src={PLATFORM_LOGO} class="!h-10 !w-10" />
|
||||
</PrimaryNavItem>
|
||||
<Divider />
|
||||
{#each getMembershipUrls($userMembership) as url (url)}
|
||||
{#each spaceUrls as url (url)}
|
||||
<PrimaryNavItemSpace {url} />
|
||||
{/each}
|
||||
<PrimaryNavItem title="Add Space" on:click={addSpace} class="tooltip-right">
|
||||
@@ -66,7 +68,7 @@
|
||||
title="Messages"
|
||||
on:click={openChat}
|
||||
class="tooltip-right"
|
||||
notification={$chatNotification}>
|
||||
notification={$notifications.has("/chat")}>
|
||||
<Avatar icon="letter" class="!h-10 !w-10" />
|
||||
</PrimaryNavItem>
|
||||
<PrimaryNavItem title="Search" href="/people" class="tooltip-right">
|
||||
@@ -88,13 +90,13 @@
|
||||
<PrimaryNavItem title="Notes" href="/notes">
|
||||
<Avatar icon="notes-minimalistic" class="!h-10 !w-10" />
|
||||
</PrimaryNavItem>
|
||||
<PrimaryNavItem title="Messages" on:click={openChat} notification={$chatNotification}>
|
||||
<PrimaryNavItem
|
||||
title="Messages"
|
||||
on:click={openChat}
|
||||
notification={$notifications.has("/chat")}>
|
||||
<Avatar icon="letter" class="!h-10 !w-10" />
|
||||
</PrimaryNavItem>
|
||||
<PrimaryNavItem
|
||||
title="Spaces"
|
||||
on:click={showSpacesMenu}
|
||||
notification={$inactiveSpacesNotifications.length > 0}>
|
||||
<PrimaryNavItem title="Spaces" on:click={showSpacesMenu} notification={anySpaceNotifications}>
|
||||
<Avatar icon="settings-minimalistic" class="!h-10 !w-10" />
|
||||
</PrimaryNavItem>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import PrimaryNavItem from "@lib/components/PrimaryNavItem.svelte"
|
||||
import SpaceAvatar from "@app/components/SpaceAvatar.svelte"
|
||||
import {makeSpacePath} from "@app/routes"
|
||||
import {spacesNotifications} from "@app/notifications"
|
||||
import {notifications} from "@app/notifications"
|
||||
|
||||
export let url
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
title={displayRelayUrl(url)}
|
||||
href={path}
|
||||
class="tooltip-right"
|
||||
notification={$spacesNotifications.includes(path)}>
|
||||
notification={$notifications.has(path)}>
|
||||
<SpaceAvatar {url} />
|
||||
</PrimaryNavItem>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import ThunkStatus from "@app/components/ThunkStatus.svelte"
|
||||
import ThreadMenu from "@app/components/ThreadMenu.svelte"
|
||||
import {publishDelete, publishReaction} from "@app/commands"
|
||||
import {deriveNotification} from "@app/notifications"
|
||||
import {notifications} from "@app/notifications"
|
||||
import {makeSpacePath} from "@app/routes"
|
||||
import {PROTECTED} from "@app/state"
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
const path = makeSpacePath(url, "threads", event.id)
|
||||
const filters = [{kinds: [COMMENT], "#E": [event.id]}]
|
||||
const replies = deriveEvents(repository, {filters})
|
||||
const notification = deriveNotification(path, filters, url)
|
||||
|
||||
const showPopover = () => popover.show()
|
||||
|
||||
@@ -70,7 +69,7 @@
|
||||
<span>{$replies.length} {$replies.length === 1 ? "reply" : "replies"}</span>
|
||||
</div>
|
||||
<div class="btn btn-neutral btn-xs relative hidden rounded-full sm:flex">
|
||||
{#if $notification}
|
||||
{#if $notifications.has(path)}
|
||||
<div class="h-2 w-2 rounded-full bg-primary" />
|
||||
{/if}
|
||||
Active {formatTimestampRelative(lastActive)}
|
||||
|
||||
+63
-75
@@ -1,16 +1,15 @@
|
||||
import {writable, derived} from "svelte/store"
|
||||
import {page} from "$app/stores"
|
||||
import {deriveEvents} from "@welshman/store"
|
||||
import {repository, pubkey} from "@welshman/app"
|
||||
import {prop, max, sortBy, assoc, lt, now} from "@welshman/lib"
|
||||
import type {Filter, TrustedEvent} from "@welshman/util"
|
||||
import {DIRECT_MESSAGE, MESSAGE, THREAD, COMMENT} from "@welshman/util"
|
||||
import {makeSpacePath, makeThreadPath, makeRoomPath} from "@app/routes"
|
||||
import {pubkey} from "@welshman/app"
|
||||
import {prop, max, sortBy, now} from "@welshman/lib"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {MESSAGE} from "@welshman/util"
|
||||
import {makeSpacePath, makeChatPath, makeThreadPath, makeRoomPath} from "@app/routes"
|
||||
import {
|
||||
LEGACY_THREAD,
|
||||
THREAD_FILTER,
|
||||
COMMENT_FILTER,
|
||||
chats,
|
||||
getEventsForUrl,
|
||||
deriveEventsForUrl,
|
||||
getMembershipUrls,
|
||||
userRoomsByUrl,
|
||||
repositoryStore,
|
||||
} from "@app/state"
|
||||
@@ -19,85 +18,74 @@ import {
|
||||
|
||||
export const checked = writable<Record<string, number>>({})
|
||||
|
||||
checked.subscribe(v => console.log("====== checked", v))
|
||||
|
||||
export const deriveChecked = (key: string) => derived(checked, prop(key))
|
||||
|
||||
export const setChecked = (key: string, ts = now()) =>
|
||||
Boolean(console.trace("====== setChecked", key)) ||
|
||||
checked.update(state => ({...state, [key]: ts}))
|
||||
export const setChecked = (key: string) =>
|
||||
checked.update(state => ({...state, [key]: now()}))
|
||||
|
||||
// Filters for various routes
|
||||
// Derived notifications state
|
||||
|
||||
export const CHAT_FILTERS: Filter[] = [{kinds: [DIRECT_MESSAGE]}]
|
||||
export const notifications = derived(
|
||||
[pubkey, checked, chats, userRoomsByUrl, repositoryStore],
|
||||
([$pubkey, $checked, $chats, $userRoomsByUrl, $repository]) => {
|
||||
const hasNotification = (path: string, events: TrustedEvent[]) => {
|
||||
const [latestEvent] = sortBy($e => -$e.created_at, events)
|
||||
|
||||
export const SPACE_FILTERS: Filter[] = [{kinds: [THREAD, MESSAGE, COMMENT]}]
|
||||
if (!latestEvent || latestEvent.pubkey === $pubkey) {
|
||||
return false
|
||||
}
|
||||
|
||||
export const ROOM_FILTERS: Filter[] = [{kinds: [MESSAGE]}]
|
||||
let checkPath = ""
|
||||
let lastChecked = $checked["*"]
|
||||
|
||||
export const THREAD_FILTERS: Filter[] = [
|
||||
{kinds: [THREAD, LEGACY_THREAD]},
|
||||
{kinds: [COMMENT], "#K": [String(THREAD), String(LEGACY_THREAD)]},
|
||||
]
|
||||
for (const segment of path.slice(1).split("/")) {
|
||||
checkPath += "/" + segment
|
||||
lastChecked = max([lastChecked, $checked[checkPath]])
|
||||
}
|
||||
|
||||
export const getNotificationFilters = (since: number): Filter[] =>
|
||||
[...CHAT_FILTERS, ...SPACE_FILTERS, ...THREAD_FILTERS].map(assoc("since", since))
|
||||
|
||||
export const getRoomFilters = (room: string): Filter[] => ROOM_FILTERS.map(assoc("#h", [room]))
|
||||
|
||||
// Notification derivation
|
||||
|
||||
export const getNotification = (
|
||||
pubkey: string | null,
|
||||
lastChecked: number,
|
||||
events: TrustedEvent[],
|
||||
) => {
|
||||
const [latestEvent] = sortBy($e => -$e.created_at, events)
|
||||
|
||||
return latestEvent?.pubkey !== pubkey && lt(lastChecked, latestEvent?.created_at)
|
||||
}
|
||||
|
||||
export const deriveNotification = (path: string, filters: Filter[], url?: string) => {
|
||||
const events = url ? deriveEventsForUrl(url, filters) : deriveEvents(repository, {filters})
|
||||
|
||||
return derived(
|
||||
[pubkey, deriveChecked("*"), deriveChecked(path), events],
|
||||
([$pubkey, $allChecked, $checked, $events]) => {
|
||||
return getNotification($pubkey, max([$allChecked, $checked]), $events)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export const spacesNotifications = derived(
|
||||
[pubkey, checked, userRoomsByUrl, repositoryStore],
|
||||
([$pubkey, $checked, $userRoomsByUrl, $repository]) => {
|
||||
const hasNotification = (url: string, path: string, filters: Filter[]) => {
|
||||
const lastChecked = max([$checked["*"], $checked[path]])
|
||||
const events = getEventsForUrl($repository, url, filters)
|
||||
|
||||
return getNotification($pubkey, lastChecked, events)
|
||||
return lastChecked < latestEvent.created_at
|
||||
}
|
||||
|
||||
return Array.from($userRoomsByUrl.entries())
|
||||
.filter(([url, rooms]) => {
|
||||
if (hasNotification(url, makeThreadPath(url), THREAD_FILTERS)) {
|
||||
return true
|
||||
}
|
||||
const paths = new Set<string>()
|
||||
|
||||
for (const room of rooms) {
|
||||
if (hasNotification(url, makeRoomPath(url, room), [{kinds: [MESSAGE], "#h": [room]}])) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for (const {pubkeys, messages} of $chats) {
|
||||
const chatPath = makeChatPath(pubkeys)
|
||||
|
||||
return false
|
||||
})
|
||||
.map(([url]) => makeSpacePath(url))
|
||||
if (hasNotification(chatPath, messages)) {
|
||||
paths.add("/chat")
|
||||
paths.add(chatPath)
|
||||
}
|
||||
}
|
||||
|
||||
for (const [url, rooms] of $userRoomsByUrl.entries()) {
|
||||
const spacePath = makeSpacePath(url)
|
||||
const threadPath = makeThreadPath(url)
|
||||
const threadFilters = [THREAD_FILTER, COMMENT_FILTER]
|
||||
const threadEvents = getEventsForUrl($repository, url, threadFilters)
|
||||
|
||||
if (hasNotification(threadPath, threadEvents)) {
|
||||
paths.add(spacePath)
|
||||
paths.add(threadPath)
|
||||
}
|
||||
|
||||
for (const room of rooms) {
|
||||
const roomPath = makeRoomPath(url, room)
|
||||
const roomFilters = [{kinds: [MESSAGE], "#h": [room]}]
|
||||
const roomEvents = getEventsForUrl($repository, url, roomFilters)
|
||||
|
||||
if (hasNotification(roomPath, roomEvents)) {
|
||||
paths.add(spacePath)
|
||||
paths.add(roomPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paths
|
||||
},
|
||||
)
|
||||
|
||||
export const inactiveSpacesNotifications = derived(
|
||||
[page, spacesNotifications],
|
||||
([$page, $spacesNotifications]) =>
|
||||
$spacesNotifications.filter(path => !$page.url.pathname.startsWith(path)),
|
||||
export const inactiveNotifications = derived(
|
||||
[page, notifications],
|
||||
([$page, $notifications]) =>
|
||||
new Set(Array.from($notifications).filter(path => !$page.url.pathname.startsWith(path))),
|
||||
)
|
||||
|
||||
+16
-2
@@ -40,7 +40,14 @@ import {
|
||||
asDecryptedEvent,
|
||||
normalizeRelayUrl,
|
||||
} from "@welshman/util"
|
||||
import type {TrustedEvent, SignedEvent, PublishedList, List, Filter} from "@welshman/util"
|
||||
import type {
|
||||
TrustedEvent,
|
||||
Repository,
|
||||
SignedEvent,
|
||||
PublishedList,
|
||||
List,
|
||||
Filter,
|
||||
} from "@welshman/util"
|
||||
import {Nip59} from "@welshman/signer"
|
||||
import {
|
||||
pubkey,
|
||||
@@ -63,7 +70,7 @@ import {
|
||||
thunks,
|
||||
walkThunks,
|
||||
} from "@welshman/app"
|
||||
import type {Thunk} from "@welshman/app"
|
||||
import type {Thunk, Relay} from "@welshman/app"
|
||||
import type {SubscribeRequestWithHandlers} from "@welshman/net"
|
||||
import {deriveEvents, deriveEventsMapped, withGetter, synced} from "@welshman/store"
|
||||
|
||||
@@ -107,6 +114,13 @@ export const IMGPROXY_URL = "https://imgproxy.coracle.social"
|
||||
|
||||
export const REACTION_KINDS = [REACTION, ZAP_RESPONSE]
|
||||
|
||||
export const THREAD_FILTER: Filter = {kinds: [THREAD, LEGACY_THREAD]}
|
||||
|
||||
export const COMMENT_FILTER: Filter = {
|
||||
kinds: [COMMENT],
|
||||
"#K": [String(THREAD), String(LEGACY_THREAD)],
|
||||
}
|
||||
|
||||
export const NIP46_PERMS =
|
||||
"nip04_encrypt,nip04_decrypt,nip44_encrypt,nip44_decrypt," +
|
||||
[CLIENT_AUTH, AUTH_JOIN, MESSAGE, THREAD, COMMENT, GROUPS, WRAP, REACTION]
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
import {setChecked} from "@app/notifications"
|
||||
import {checkRelayConnection, checkRelayAuth, checkRelayAccess} from "@app/commands"
|
||||
import {decodeRelay} from "@app/state"
|
||||
import {spacesNotifications} from "@app/notifications"
|
||||
import {notifications} from "@app/notifications"
|
||||
|
||||
const url = decodeRelay($page.params.relay)
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
// We have to watch this one, since on mobile the badge will be visible when active
|
||||
$: {
|
||||
if ($spacesNotifications.includes($page.url.pathname)) {
|
||||
if ($notifications.has($page.url.pathname)) {
|
||||
setChecked($page.url.pathname)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import {derived} from "svelte/store"
|
||||
import {page} from "$app/stores"
|
||||
import {sortBy, min, nthEq, sleep} from "@welshman/lib"
|
||||
import {getListTags, getPubkeyTagValues, THREAD, COMMENT} from "@welshman/util"
|
||||
import {getListTags, getPubkeyTagValues} from "@welshman/util"
|
||||
import {throttled} from "@welshman/store"
|
||||
import {feedsFromFilters, makeIntersectionFeed, makeRelayFeed} from "@welshman/feeds"
|
||||
import {createFeedController, userMutes} from "@welshman/app"
|
||||
@@ -16,15 +16,14 @@
|
||||
import MenuSpaceButton from "@app/components/MenuSpaceButton.svelte"
|
||||
import ThreadItem from "@app/components/ThreadItem.svelte"
|
||||
import ThreadCreate from "@app/components/ThreadCreate.svelte"
|
||||
import {LEGACY_THREAD, decodeRelay, deriveEventsForUrl} from "@app/state"
|
||||
import {THREAD_FILTERS, setChecked} from "@app/notifications"
|
||||
import {THREAD_FILTER, COMMENT_FILTER, decodeRelay, deriveEventsForUrl} from "@app/state"
|
||||
import {setChecked} from "@app/notifications"
|
||||
import {pushModal} from "@app/modal"
|
||||
|
||||
const url = decodeRelay($page.params.relay)
|
||||
const threads = deriveEventsForUrl(url, [{kinds: [THREAD, LEGACY_THREAD]}])
|
||||
const comments = deriveEventsForUrl(url, [
|
||||
{kinds: [COMMENT], "#K": [String(THREAD), String(LEGACY_THREAD)]},
|
||||
])
|
||||
const feeds = feedsFromFilters([THREAD_FILTER, COMMENT_FILTER])
|
||||
const threads = deriveEventsForUrl(url, [THREAD_FILTER])
|
||||
const comments = deriveEventsForUrl(url, [COMMENT_FILTER])
|
||||
const mutedPubkeys = getPubkeyTagValues(getListTags($userMutes))
|
||||
|
||||
const events = throttled(
|
||||
@@ -51,7 +50,7 @@
|
||||
|
||||
const ctrl = createFeedController({
|
||||
useWindowing: true,
|
||||
feed: makeIntersectionFeed(makeRelayFeed(url), feedsFromFilters(THREAD_FILTERS)),
|
||||
feed: makeIntersectionFeed(makeRelayFeed(url), feeds),
|
||||
onExhausted: () => {
|
||||
loading = false
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user