From ce1fb396e31669f09e7b602846cdb5395c1ec8b8 Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Tue, 28 Jan 2025 14:19:26 -0800 Subject: [PATCH] Add button to scroll to new messages in channel --- CHANGELOG.md | 1 + src/routes/spaces/[relay]/[room]/+page.svelte | 59 +++++++++++++++++-- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac6ef98..aa979b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Add reply to long-press menu * Fix @-mentions * Replace nsec.app signup with njump.me +* Add new messages button in rooms # 0.2.5 diff --git a/src/routes/spaces/[relay]/[room]/+page.svelte b/src/routes/spaces/[relay]/[room]/+page.svelte index cf3c6ca..71917e7 100644 --- a/src/routes/spaces/[relay]/[room]/+page.svelte +++ b/src/routes/spaces/[relay]/[room]/+page.svelte @@ -6,7 +6,7 @@ import type {TrustedEvent, EventContent} from "@welshman/util" import {createEvent, MESSAGE, DELETE, REACTION} from "@welshman/util" import {formatTimestampAsDate, publishThunk, deriveRelay, repository} from "@welshman/app" - import {slide, fade} from "@lib/transition" + import {slide, fade, fly} from "@lib/transition" import Icon from "@lib/components/Icon.svelte" import Button from "@lib/components/Button.svelte" import Spinner from "@lib/components/Spinner.svelte" @@ -26,7 +26,7 @@ displayChannel, getEventsForUrl, } from "@app/state" - import {setChecked} from "@app/notifications" + import {setChecked, checked} from "@app/notifications" import { nip29, addRoomMembership, @@ -40,6 +40,7 @@ import {pushToast} from "@app/toast" const {room = GENERAL} = $page.params + const lastChecked = $checked[$page.url.pathname] const content = popKey("content") || "" const url = decodeRelay($page.params.relay) const filter = {kinds: [MESSAGE], "#h": [room]} @@ -89,11 +90,33 @@ clearParent() } + const onScroll = () => { + showScrollButton = Math.abs(element?.scrollTop || 0) > 1500 + + if (!newMessages || newMessagesSeen) { + showFixedNewMessages = false + } else { + const {y} = newMessages.getBoundingClientRect() + + if (y > 300) { + newMessagesSeen = true + } else { + showFixedNewMessages = y < 0 + } + } + } + + const scrollToNewMessages = () => + newMessages.scrollIntoView({behavior: "smooth", block: "center"}) + const scrollToBottom = () => element.scrollTo({top: 0, behavior: "smooth"}) let parent: TrustedEvent | undefined let loading = true let element: HTMLElement + let newMessages: HTMLElement + let newMessagesSeen = false + let showFixedNewMessages = false let showScrollButton = false let cleanup: () => void let events: Readable @@ -107,6 +130,7 @@ let previousDate let previousPubkey + let newMessagesSeen = false if (events) { for (const event of $events.toReversed()) { @@ -118,6 +142,11 @@ const date = formatTimestampAsDate(created_at) + if (!newMessagesSeen && lastChecked && created_at > lastChecked) { + elements.push({type: "new-messages", id: "new-messages"}) + newMessagesSeen = true + } + if (date !== previousDate) { elements.push({type: "date", value: date, id: date, showPubkey: false}) } @@ -136,13 +165,12 @@ } elements.reverse() + + setTimeout(onScroll, 100) } $: { if (element) { - element.addEventListener("scroll", () => { - showScrollButton = Math.abs(element.scrollTop) > 1500 - }) ;({events, cleanup} = makeFeed({ element, relays: [url], @@ -191,9 +219,19 @@
{#each elements as { type, id, value, showPubkey } (id)} - {#if type === "date"} + {#if type === "new-messages"} +
+
+

New Messages

+
+
+ {:else if type === "date"} {value} {:else}
@@ -209,6 +247,15 @@ {/if}

+ {#if showFixedNewMessages} +
+
+ +
+
+ {/if}
{#if parent}