diff options
| -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"> |
