diff options
| author | Kit La Touche <kit@transneptune.net> | 2024-11-29 14:38:57 -0500 |
|---|---|---|
| committer | Kit La Touche <kit@transneptune.net> | 2024-11-29 14:41:17 -0500 |
| commit | 0276d22c9ed49b035129cac99f68ada7fc1015d2 (patch) | |
| tree | 216842b15b55181a495af1643102718bbe041a38 /ui | |
| parent | e0d93f326722609a0ba50da106ace9b7a43bbc7b (diff) | |
Set last-read on a channel on some events
Esc key, 2 second wait after scroll, and whenever the messages inChannel
change. Kinda gross set of things, but, so it goes. This does offer us
the option of extending this to include "when you click 'unread from
here' on a message" in future.
Diffstat (limited to 'ui')
| -rw-r--r-- | ui/routes/(app)/ch/[channel]/+page.svelte | 60 |
1 files changed, 58 insertions, 2 deletions
diff --git a/ui/routes/(app)/ch/[channel]/+page.svelte b/ui/routes/(app)/ch/[channel]/+page.svelte index 0961665..7d5b8cf 100644 --- a/ui/routes/(app)/ch/[channel]/+page.svelte +++ b/ui/routes/(app)/ch/[channel]/+page.svelte @@ -1,14 +1,70 @@ <script> + import { DateTime } from 'luxon'; import { page } from '$app/stores'; import ActiveChannel from '$lib/components/ActiveChannel.svelte'; import MessageInput from '$lib/components/MessageInput.svelte'; - import { messages } from '$lib/store'; + import { channelsList, messages } from '$lib/store'; let channel = $derived($page.params.channel); let messageRuns = $derived($messages.inChannel(channel)); + let activeChannel; + + function inView(parentElement, element) { + const parRect = parentElement.getBoundingClientRect(); + const parentTop = parRect.top; + const parentBottom = parRect.bottom; + + const elRect = element.getBoundingClientRect(); + const elementTop = elRect.top; + const elementBottom = elRect.bottom; + + return ((parentTop < elementTop) && (parentBottom > elementBottom)); + } + + function getLastVisibleMessage() { + const parentElement = activeChannel; + const childElements = parentElement.getElementsByClassName('message'); + const lastInView = Array.from(childElements).reverse().find((el) => { + return inView(parentElement, el); + }); + return lastInView; + } + + function setLastRead() { + const channelObject = $channelsList.getChannel(channel); + const lastInView = getLastVisibleMessage(); + if (!channelObject || !lastInView) { + return; + } + const at = DateTime.fromISO(lastInView.dataset.at); + // Do it this way, rather than with Math.max tricks, to avoid assignment + // when we don't need it, to minimize reactive changes: + if (at > channelObject.lastReadAt) { + channelObject.lastReadAt = at; + } + } + + $effect(() => { + const _ = $messages.inChannel(channel); + setLastRead(); + }); + + function handleKeydown(event) { + if (event.key === 'Escape') { + setLastRead(); // TODO: pass in "last message DT"? + } + } + + let lastReadCallback = null; + function handleScroll() { + clearTimeout(lastReadCallback); // Fine if lastReadCallback is null still. + lastReadCallback = setTimeout(setLastRead, 2 * 1000); + } </script> -<div class="active-channel"> +<svelte:window onkeydown={handleKeydown} /> + +<div class="active-channel" on:scroll={handleScroll} bind:this={activeChannel}> <ActiveChannel {messageRuns} /> </div> <div class="create-message max-h-full"> |
