summaryrefslogtreecommitdiff
path: root/ui/routes/(app)
diff options
context:
space:
mode:
authorKit La Touche <kit@transneptune.net>2024-11-29 14:38:57 -0500
committerKit La Touche <kit@transneptune.net>2024-11-29 14:41:17 -0500
commit0276d22c9ed49b035129cac99f68ada7fc1015d2 (patch)
tree216842b15b55181a495af1643102718bbe041a38 /ui/routes/(app)
parente0d93f326722609a0ba50da106ace9b7a43bbc7b (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/routes/(app)')
-rw-r--r--ui/routes/(app)/ch/[channel]/+page.svelte60
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">