Add notification badges

This commit is contained in:
Jon Staab
2024-11-14 10:53:13 -08:00
parent b296067e55
commit 14ad4ec785
21 changed files with 256 additions and 126 deletions
+9 -2
View File
@@ -1,14 +1,16 @@
<script lang="ts">
import {onMount} from "svelte"
import {page} from "$app/stores"
import {remove} from "@welshman/lib"
import {remove, assoc} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util"
import {pubkey, loadInboxRelaySelections} from "@welshman/app"
import {fade} from "@lib/transition"
import Link from "@lib/components/Link.svelte"
import ProfileName from "@app/components/ProfileName.svelte"
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"
export let id: string
export let pubkeys: string[]
@@ -17,6 +19,8 @@
const message = messages[0]
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) {
@@ -30,7 +34,7 @@
class="cursor-pointer border-t border-solid border-base-100 px-6 py-2 transition-colors hover:bg-base-100 {$$props.class}"
class:bg-base-100={active}>
<div class="flex flex-col justify-start gap-1">
<div class="flex justify-between gap-2">
<div class="flex items-center justify-between gap-2">
<div class="flex min-w-0 items-center gap-2">
{#if others.length === 1}
<ProfileCircle pubkey={others[0]} size={5} />
@@ -44,6 +48,9 @@
</p>
{/if}
</div>
{#if !active && $notification}
<div class="h-2 w-2 rounded-full bg-primary" transition:fade />
{/if}
</div>
<p class="overflow-hidden text-ellipsis whitespace-nowrap text-sm">
{message.content}
+2
View File
@@ -13,6 +13,7 @@
import {PLATFORM_NAME} from "@app/state"
import {pushToast} from "@app/toast"
import {loadUserData} from "@app/commands"
import {setChecked} from "@app/notifications"
const signUp = () => pushModal(SignUp)
@@ -32,6 +33,7 @@
await loadUserData(session.pubkey, {relays})
pushToast({message: "Successfully logged in!"})
setChecked("*")
clearModals()
}
+2
View File
@@ -13,6 +13,7 @@
import InfoBunker from "@app/components/InfoBunker.svelte"
import {loginWithNip46, loadUserData} from "@app/commands"
import {pushModal, clearModals} from "@app/modal"
import {setChecked} from "@app/notifications"
import {pushToast} from "@app/toast"
import {PLATFORM_URL, PLATFORM_NAME, PLATFORM_LOGO, SIGNER_RELAYS} from "@app/state"
@@ -79,6 +80,7 @@
await loadUserData(pubkey)
setChecked("*")
clearModals()
}
})
+8 -9
View File
@@ -13,6 +13,7 @@
import SpaceJoin from "@app/components/SpaceJoin.svelte"
import ProfileList from "@app/components/ProfileList.svelte"
import RoomCreate from "@app/components/RoomCreate.svelte"
import MenuSpaceRoomItem from "@app/components/MenuSpaceRoomItem.svelte"
import {
getMembershipRoomsByUrl,
getMembershipUrls,
@@ -22,11 +23,15 @@
roomsByUrl,
GENERAL,
} from "@app/state"
import {deriveNotification, THREAD_FILTERS} from "@app/notifications"
import {pushModal} from "@app/modal"
import {makeSpacePath} from "@app/routes"
export let url
const threadsPath = makeSpacePath(url, "threads")
const threadsNotification = deriveNotification(threadsPath, THREAD_FILTERS, url)
const openMenu = () => {
showMenu = true
}
@@ -121,7 +126,7 @@
</SecondaryNavItem>
</div>
<div in:fly={{delay: getDelay()}}>
<SecondaryNavItem href={makeSpacePath(url, "threads")}>
<SecondaryNavItem href={threadsPath} notification={$threadsNotification}>
<Icon icon="notes-minimalistic" /> Threads
</SecondaryNavItem>
</div>
@@ -130,17 +135,11 @@
<SecondaryNavHeader>Your Rooms</SecondaryNavHeader>
</div>
<div transition:slide={{delay: getDelay()}}>
<SecondaryNavItem href={makeSpacePath(url, GENERAL)}>
<Icon icon="hashtag" />
{GENERAL}
</SecondaryNavItem>
<MenuSpaceRoomItem {url} room={GENERAL} />
</div>
{#each rooms as room, i (room)}
<div transition:slide={{delay: getDelay()}}>
<SecondaryNavItem href={makeSpacePath(url, room)}>
<Icon icon="hashtag" />
{room}
</SecondaryNavItem>
<MenuSpaceRoomItem {url} {room} />
</div>
{/each}
{#if otherRooms.length > 0}
@@ -0,0 +1,17 @@
<script lang="ts">
import Icon from "@lib/components/Icon.svelte"
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
import {makeSpacePath} from "@app/routes"
import {deriveNotification, getRoomFilters} from "@app/notifications"
export let url
export let room
const path = makeSpacePath(url, room)
const notification = deriveNotification(path, getRoomFilters(room), url)
</script>
<SecondaryNavItem href={path} notification={$notification}>
<Icon icon="hashtag" />
{room}
</SecondaryNavItem>
+11 -16
View File
@@ -1,16 +1,17 @@
<script lang="ts">
import {displayRelayUrl} from "@welshman/util"
import {userProfile} from "@welshman/app"
import Avatar from "@lib/components/Avatar.svelte"
import Divider from "@lib/components/Divider.svelte"
import PrimaryNavItem from "@lib/components/PrimaryNavItem.svelte"
import SpaceAdd from "@app/components/SpaceAdd.svelte"
import SpaceAvatar from "@app/components/SpaceAvatar.svelte"
import MenuSpaces from "@app/components/MenuSpaces.svelte"
import MenuSettings from "@app/components/MenuSettings.svelte"
import PrimaryNavItemSpace from "@app/components/PrimaryNavItemSpace.svelte"
import {userMembership, getMembershipUrls, PLATFORM_RELAY, PLATFORM_LOGO} from "@app/state"
import {pushModal} from "@app/modal"
import {makeSpacePath} from "@app/routes"
import {deriveNotification, CHAT_FILTERS} from "@app/notifications"
const chatNotification = deriveNotification("/chat", CHAT_FILTERS)
const addSpace = () => pushModal(SpaceAdd)
@@ -24,24 +25,14 @@
<div class="flex h-full flex-col justify-between">
<div>
{#if PLATFORM_RELAY}
<PrimaryNavItem
title={displayRelayUrl(PLATFORM_RELAY)}
href={makeSpacePath(PLATFORM_RELAY)}
class="tooltip-right">
<SpaceAvatar url={PLATFORM_RELAY} />
</PrimaryNavItem>
<PrimaryNavItemSpace url={PLATFORM_RELAY} />
{:else}
<PrimaryNavItem title="Home" href="/home" class="tooltip-right">
<Avatar src={PLATFORM_LOGO} class="!h-10 !w-10" />
</PrimaryNavItem>
<Divider />
{#each getMembershipUrls($userMembership) as url (url)}
<PrimaryNavItem
title={displayRelayUrl(url)}
href={makeSpacePath(url)}
class="tooltip-right">
<SpaceAvatar {url} />
</PrimaryNavItem>
<PrimaryNavItemSpace {url} />
{/each}
<PrimaryNavItem title="Add Space" on:click={addSpace} class="tooltip-right">
<Avatar icon="settings-minimalistic" class="!h-10 !w-10" />
@@ -59,7 +50,11 @@
<PrimaryNavItem title="Notes" href="/notes" class="tooltip-right">
<Avatar icon="notes-minimalistic" class="!h-10 !w-10" />
</PrimaryNavItem>
<PrimaryNavItem title="Messages" href="/chat" class="tooltip-right">
<PrimaryNavItem
title="Messages"
href="/chat"
class="tooltip-right"
notification={$chatNotification}>
<Avatar icon="letter" class="!h-10 !w-10" />
</PrimaryNavItem>
<PrimaryNavItem title="Search" href="/people" class="tooltip-right">
@@ -0,0 +1,20 @@
<script lang="ts">
import {displayRelayUrl} from "@welshman/util"
import PrimaryNavItem from "@lib/components/PrimaryNavItem.svelte"
import SpaceAvatar from "@app/components/SpaceAvatar.svelte"
import {makeSpacePath} from "@app/routes"
import {deriveNotification, SPACE_FILTERS} from "@app/notifications"
export let url
const path = makeSpacePath(url)
const notification = deriveNotification(path, SPACE_FILTERS, url)
</script>
<PrimaryNavItem
title={displayRelayUrl(url)}
href={path}
class="tooltip-right"
notification={$notification}>
<SpaceAvatar {url} />
</PrimaryNavItem>
+2
View File
@@ -10,6 +10,7 @@
import LogIn from "@app/components/LogIn.svelte"
import InfoNostr from "@app/components/InfoNostr.svelte"
import {pushModal, clearModals} from "@app/modal"
import {setChecked} from "@app/notifications"
import {PLATFORM_NAME} from "@app/state"
import {pushToast} from "@app/toast"
@@ -42,6 +43,7 @@
if (await loginBroker.connect("", nip46Perms)) {
addSession({method: "nip46", pubkey, secret, handler: {...handler, pubkey}})
pushToast({message: "Successfully logged in!"})
setChecked("*")
clearModals()
} else {
pushToast({
+10 -2
View File
@@ -13,6 +13,8 @@
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 {makeSpacePath} from "@app/routes"
import {COMMENT} from "@app/state"
export let url
@@ -21,7 +23,10 @@
const thunk = $thunks[event.id]
const deleted = deriveIsDeleted(repository, event)
const replies = deriveEvents(repository, {filters: [{kinds: [COMMENT], "#E": [event.id]}]})
const path = makeSpacePath(url, "threads", event.id)
const filters = [{kinds: [COMMENT], "#E": [event.id]}]
const notification = deriveNotification(path, filters, url)
const replies = deriveEvents(repository, {filters})
const showPopover = () => popover.show()
@@ -58,7 +63,10 @@
<Icon icon="reply" />
<span>{$replies.length} {$replies.length === 1 ? "reply" : "replies"}</span>
</div>
<div class="btn btn-neutral btn-xs hidden rounded-full sm:flex">
<div class="btn btn-neutral btn-xs relative hidden rounded-full sm:flex">
{#if $notification}
<div class="h-2 w-2 rounded-full bg-primary" />
{/if}
Active {formatTimestampRelative(lastActive)}
</div>
{/if}