fix: stabilize list loading and show correct list count

This commit is contained in:
Bhavishy
2026-04-14 19:26:43 +05:30
parent 2cea6c4ef4
commit 0db751bd45
13 changed files with 792 additions and 491 deletions
+104 -8
View File
@@ -1,6 +1,18 @@
<script lang="ts">
import type {Snippet} from "svelte"
import {userProfile} from "@welshman/app"
import {onMount} from "svelte"
import {uniqBy} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util"
import {
Address,
DELETE,
getAddress,
getTagValue,
getTagValues,
sortEventsDesc,
} from "@welshman/util"
import {load} from "@welshman/net"
import {pubkey, userProfile} from "@welshman/app"
import Letter from "@assets/icons/letter.svg?dataurl"
import Bookmark from "@assets/icons/bookmark.svg?dataurl"
import Magnifier from "@assets/icons/magnifier.svg?dataurl"
@@ -8,11 +20,19 @@
import UserRounded from "@assets/icons/user-rounded.svg?dataurl"
import Settings from "@assets/icons/settings.svg?dataurl"
import ImageIcon from "@lib/components/ImageIcon.svelte"
import Divider from "@lib/components/Divider.svelte"
import MenuSettings from "@app/components/MenuSettings.svelte"
import PrimaryNavItem from "@lib/components/PrimaryNavItem.svelte"
import PrimaryNavSpaces from "@app/components/PrimaryNavSpaces.svelte"
import {userSpaceUrls, PLATFORM_RELAYS} from "@app/core/state"
import {
BOOKMARKS,
BOOKMARK_LISTS,
deriveEvents,
INDEXER_RELAYS,
loadUserBookmarkCollections,
loadUserBookmarkList,
userSpaceUrls,
PLATFORM_RELAYS,
} from "@app/core/state"
import {pushModal} from "@app/util/modal"
import {notifications} from "@app/util/notifications"
import {goToChat, makeSpacePath} from "@app/util/routes"
@@ -30,18 +50,90 @@
const anySpaceNotifications = $derived(
$userSpaceUrls.some(p => $notifications.has(makeSpacePath(p))),
)
const bookmarkListEvents = deriveEvents([{kinds: [BOOKMARKS, BOOKMARK_LISTS, DELETE]}])
let loadedBookmarkCountPubkey: string | undefined = $state()
const getListKey = (event: TrustedEvent) =>
event.kind === BOOKMARKS
? new Address(BOOKMARKS, event.pubkey, "").toString()
: getAddress(event)
const isDeletedList = (event: TrustedEvent, deleteEvents: TrustedEvent[]) => {
const address =
event.kind === BOOKMARKS
? new Address(BOOKMARKS, event.pubkey, "").toString()
: `${event.kind}:${event.pubkey}:${getTagValue("d", event.tags) || ""}`
return deleteEvents.some(deleteEvent => {
if (deleteEvent.created_at < event.created_at) {
return false
}
return (
getTagValues("e", deleteEvent.tags).includes(event.id) ||
getTagValues("a", deleteEvent.tags).includes(address)
)
})
}
const bookmarkListCount = $derived.by(() => {
if (!$pubkey) {
return 0
}
const ownEvents = sortEventsDesc($bookmarkListEvents).filter(event => event.pubkey === $pubkey)
const deleteEvents = ownEvents.filter(event => event.kind === DELETE)
const listEvents = ownEvents.filter(
event => event.kind === BOOKMARKS || event.kind === BOOKMARK_LISTS,
)
const visibleLists = uniqBy(getListKey, listEvents).filter(
event => !isDeletedList(event, deleteEvents),
)
const hasSavedItems = visibleLists.some(event => event.kind === BOOKMARKS)
return visibleLists.length + (hasSavedItems ? 0 : 1)
})
const loadBookmarkCountData = async () => {
if (!$pubkey || loadedBookmarkCountPubkey === $pubkey) {
return
}
loadedBookmarkCountPubkey = $pubkey
await Promise.all([
loadUserBookmarkList(),
loadUserBookmarkCollections(),
load({
relays: INDEXER_RELAYS,
filters: [{kinds: [DELETE], authors: [$pubkey]}],
}),
])
}
onMount(() => {
void loadBookmarkCountData()
})
$effect(() => {
if ($pubkey && loadedBookmarkCountPubkey !== $pubkey) {
void loadBookmarkCountData()
}
})
</script>
<div
class="ml-sai mt-sai mb-sai relative z-popover isolate hidden w-14 shrink-0 bg-base-200 pt-2 md:block">
<div class="flex h-full flex-col" class:justify-between={PLATFORM_RELAYS.length === 0}>
<PrimaryNavSpaces />
{#if PLATFORM_RELAYS.length > 0}
<Divider />
{/if}
<div class="flex flex-col">
<PrimaryNavItem title="Bookmarks" href="/bookmarks" prefix="/bookmarks">
<ImageIcon alt="Bookmarks" src={Bookmark} size={8} />
<div class="relative">
<ImageIcon alt="Bookmarks" src={Bookmark} size={8} />
<span class="badge badge-xs badge-neutral absolute -right-2 -top-2"
>{bookmarkListCount}</span>
</div>
</PrimaryNavItem>
<PrimaryNavItem title="Settings" href="/settings/profile" prefix="/settings">
{#if $userProfile?.picture}
@@ -83,7 +175,11 @@
<ImageIcon alt="Messages" src={Letter} size={8} />
</PrimaryNavItem>
<PrimaryNavItem title="Bookmarks" href="/bookmarks" prefix="/bookmarks">
<ImageIcon alt="Bookmarks" src={Bookmark} size={8} />
<div class="relative">
<ImageIcon alt="Bookmarks" src={Bookmark} size={8} />
<span class="badge badge-xs badge-neutral absolute -right-2 -top-2"
>{bookmarkListCount}</span>
</div>
</PrimaryNavItem>
{#if PLATFORM_RELAYS.length !== 1}
<PrimaryNavItem title="Spaces" href="/spaces" notification={anySpaceNotifications}>