Fix squirrely notification badges

This commit is contained in:
Jon Staab
2024-12-11 14:10:20 -08:00
parent c83461688f
commit 167cd045f4
6 changed files with 26 additions and 28 deletions
+2 -2
View File
@@ -5,7 +5,7 @@
import RelayName from "@app/components/RelayName.svelte" import RelayName from "@app/components/RelayName.svelte"
import RelayDescription from "@app/components/RelayDescription.svelte" import RelayDescription from "@app/components/RelayDescription.svelte"
import {makeSpacePath} from "@app/routes" import {makeSpacePath} from "@app/routes"
import {spacesNotifications} from "@app/notifications" import {inactiveSpacesNotifications} from "@app/notifications"
export let url export let url
@@ -17,7 +17,7 @@
<div slot="icon"><SpaceAvatar {url} /></div> <div slot="icon"><SpaceAvatar {url} /></div>
<div slot="title" class="flex gap-1"> <div slot="title" class="flex gap-1">
<RelayName {url} /> <RelayName {url} />
{#if $spacesNotifications.includes(url)} {#if $inactiveSpacesNotifications.includes(path)}
<div class="relative top-1 h-2 w-2 rounded-full bg-primary" /> <div class="relative top-1 h-2 w-2 rounded-full bg-primary" />
{/if} {/if}
</div> </div>
@@ -3,18 +3,17 @@
import PrimaryNavItem from "@lib/components/PrimaryNavItem.svelte" import PrimaryNavItem from "@lib/components/PrimaryNavItem.svelte"
import SpaceAvatar from "@app/components/SpaceAvatar.svelte" import SpaceAvatar from "@app/components/SpaceAvatar.svelte"
import {makeSpacePath} from "@app/routes" import {makeSpacePath} from "@app/routes"
import {deriveNotification, SPACE_FILTERS} from "@app/notifications" import {spacesNotifications} from "@app/notifications"
export let url export let url
const path = makeSpacePath(url) const path = makeSpacePath(url)
const notification = deriveNotification(path, SPACE_FILTERS, url)
</script> </script>
<PrimaryNavItem <PrimaryNavItem
title={displayRelayUrl(url)} title={displayRelayUrl(url)}
href={path} href={path}
class="tooltip-right" class="tooltip-right"
notification={$notification}> notification={$spacesNotifications.includes(path)}>
<SpaceAvatar {url} /> <SpaceAvatar {url} />
</PrimaryNavItem> </PrimaryNavItem>
+6 -3
View File
@@ -13,6 +13,7 @@
export let url export let url
export let pubkey export let pubkey
export let events: TrustedEvent[] = [] export let events: TrustedEvent[] = []
export let hideLoading = false
const ctrl = createFeedController({ const ctrl = createFeedController({
useWindowing: true, useWindowing: true,
@@ -59,8 +60,10 @@
<NoteItem {url} {event} /> <NoteItem {url} {event} />
</div> </div>
{/each} {/each}
<p class="center my-12 flex"> {#if !hideLoading}
<Spinner loading /> <p class="center my-12 flex">
</p> <Spinner loading />
</p>
{/if}
</div> </div>
</div> </div>
+10 -8
View File
@@ -17,7 +17,7 @@ checked.subscribe(v => console.log("====== checked", v))
export const deriveChecked = (key: string) => derived(checked, prop(key)) export const deriveChecked = (key: string) => derived(checked, prop(key))
export const setChecked = (key: string, ts = now()) => export const setChecked = (key: string, ts = now()) =>
Boolean(console.trace("====== setChecked", key))|| Boolean(console.trace("====== setChecked", key)) ||
checked.update(state => ({...state, [key]: ts})) checked.update(state => ({...state, [key]: ts}))
// Filters for various routes // Filters for various routes
@@ -64,18 +64,20 @@ export const deriveNotification = (path: string, filters: Filter[], url?: string
export const spacesNotifications = derived( export const spacesNotifications = derived(
[pubkey, checked, userMembership, deriveEvents(repository, {filters: SPACE_FILTERS})], [pubkey, checked, userMembership, deriveEvents(repository, {filters: SPACE_FILTERS})],
([$pubkey, $checked, $userMembership, $events]) => { ([$pubkey, $checked, $userMembership, $events]) => {
return getMembershipUrls($userMembership).filter(url => { return getMembershipUrls($userMembership)
const path = makeSpacePath(url) .filter(url => {
const lastChecked = max([$checked["*"], $checked[path]]) const path = makeSpacePath(url)
const [latestEvent] = sortBy($e => -$e.created_at, $events) const lastChecked = max([$checked["*"], $checked[path]])
const [latestEvent] = sortBy($e => -$e.created_at, $events)
return latestEvent?.pubkey !== $pubkey && lt(lastChecked, latestEvent?.created_at) return latestEvent?.pubkey !== $pubkey && lt(lastChecked, latestEvent?.created_at)
}) })
.map(url => makeSpacePath(url))
}, },
) )
export const inactiveSpacesNotifications = derived( export const inactiveSpacesNotifications = derived(
[page, spacesNotifications], [page, spacesNotifications],
([$page, $spacesNotifications]) => ([$page, $spacesNotifications]) =>
$spacesNotifications.filter(url => !$page.url.pathname.startsWith(makeSpacePath(url))), $spacesNotifications.filter(path => !$page.url.pathname.startsWith(path)),
) )
+3 -5
View File
@@ -13,12 +13,10 @@
import {setChecked} from "@app/notifications" import {setChecked} from "@app/notifications"
import {checkRelayConnection, checkRelayAuth, checkRelayAccess} from "@app/commands" import {checkRelayConnection, checkRelayAuth, checkRelayAccess} from "@app/commands"
import {decodeRelay} from "@app/state" import {decodeRelay} from "@app/state"
import {deriveNotification, SPACE_FILTERS} from "@app/notifications" import {spacesNotifications} from "@app/notifications"
const url = decodeRelay($page.params.relay) const url = decodeRelay($page.params.relay)
const notification = deriveNotification($page.url.pathname, SPACE_FILTERS, url)
const checkConnection = async () => { const checkConnection = async () => {
const connectionError = await checkRelayConnection(url) const connectionError = await checkRelayConnection(url)
@@ -35,9 +33,9 @@
} }
} }
// We have to watch this one, since on mobile the badge wil be visible when active // We have to watch this one, since on mobile the badge will be visible when active
$: { $: {
if ($notification) { if ($spacesNotifications.includes($page.url.pathname)) {
setChecked($page.url.pathname) setChecked($page.url.pathname)
} }
} }
+3 -7
View File
@@ -120,9 +120,7 @@
<Icon icon="notes-minimalistic" /> Threads <Icon icon="notes-minimalistic" /> Threads
</Link> </Link>
{#each $userRooms as room (room)} {#each $userRooms as room (room)}
<Link <Link href={makeRoomPath(url, room)} class="btn btn-neutral">
href={makeRoomPath(url, room)}
class="btn btn-neutral">
{#if channelIsLocked($channelsById.get(makeChannelId(url, room)))} {#if channelIsLocked($channelsById.get(makeChannelId(url, room)))}
<Icon icon="lock" size={4} /> <Icon icon="lock" size={4} />
{:else} {:else}
@@ -132,9 +130,7 @@
</Link> </Link>
{/each} {/each}
{#each $otherRooms as room (room)} {#each $otherRooms as room (room)}
<Link <Link href={makeRoomPath(url, room)} class="btn btn-neutral">
href={makeRoomPath(url, room)}
class="btn btn-neutral">
{#if channelIsLocked($channelsById.get(makeChannelId(url, room)))} {#if channelIsLocked($channelsById.get(makeChannelId(url, room)))}
<Icon icon="lock" size={4} /> <Icon icon="lock" size={4} />
{:else} {:else}
@@ -151,7 +147,7 @@
{#if pubkey} {#if pubkey}
<div class="hidden flex-col gap-2" class:!flex={relayAdminEvents.length > 0}> <div class="hidden flex-col gap-2" class:!flex={relayAdminEvents.length > 0}>
<Divider>Recent posts from the relay admin</Divider> <Divider>Recent posts from the relay admin</Divider>
<ProfileFeed {url} {pubkey} bind:events={relayAdminEvents} /> <ProfileFeed hideLoading {url} {pubkey} bind:events={relayAdminEvents} />
</div> </div>
{/if} {/if}
</div> </div>