Browse Source

enh: infinite scroll messages

Timothy J. Baek 7 months ago
parent
commit
d7b64ff447
2 changed files with 49 additions and 6 deletions
  1. 30 3
      src/lib/components/chat/Messages.svelte
  2. 19 3
      src/lib/components/common/Loader.svelte

+ 30 - 3
src/lib/components/chat/Messages.svelte

@@ -9,6 +9,8 @@
 
 
 	import Placeholder from './Messages/Placeholder.svelte';
 	import Placeholder from './Messages/Placeholder.svelte';
 	import Message from './Messages/Message.svelte';
 	import Message from './Messages/Message.svelte';
+	import Loader from '../common/Loader.svelte';
+	import Spinner from '../common/Spinner.svelte';
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
@@ -33,12 +35,21 @@
 	export let bottomPadding = false;
 	export let bottomPadding = false;
 	export let autoScroll;
 	export let autoScroll;
 
 
+	let messagesCount = 20;
+	let messagesLoading = false;
+
+	const loadMoreMessages = async () => {
+		messagesLoading = true;
+		messagesCount += 20;
+		messagesLoading = false;
+	};
+
 	$: if (history.currentId) {
 	$: if (history.currentId) {
 		let _messages = [];
 		let _messages = [];
 
 
 		let message = history.messages[history.currentId];
 		let message = history.messages[history.currentId];
-		while (message) {
-			_messages.unshift({ ...message });
+		while (message && _messages.length <= messagesCount) {
+			_messages.push({ ...message });
 			message = message.parentId !== null ? history.messages[message.parentId] : null;
 			message = message.parentId !== null ? history.messages[message.parentId] : null;
 		}
 		}
 
 
@@ -330,7 +341,7 @@
 	{:else}
 	{:else}
 		<div class="w-full pt-2">
 		<div class="w-full pt-2">
 			{#key chatId}
 			{#key chatId}
-				<div class="w-full">
+				<div class="w-full flex flex-col-reverse">
 					{#each messages as message, messageIdx (message.id)}
 					{#each messages as message, messageIdx (message.id)}
 						<Message
 						<Message
 							{chatId}
 							{chatId}
@@ -361,6 +372,22 @@
 							}}
 							}}
 						/>
 						/>
 					{/each}
 					{/each}
+
+					{#if messages.at(-1).parentId !== null}
+						<Loader
+							on:visible={(e) => {
+								console.log('visible');
+								if (!messagesLoading) {
+									loadMoreMessages();
+								}
+							}}
+						>
+							<div class="w-full flex justify-center py-1 text-xs animate-pulse items-center gap-2">
+								<Spinner className=" size-4" />
+								<div class=" ">Loading...</div>
+							</div>
+						</Loader>
+					{/if}
 				</div>
 				</div>
 				<div class="pb-12" />
 				<div class="pb-12" />
 				{#if bottomPadding}
 				{#if bottomPadding}

+ 19 - 3
src/lib/components/common/Loader.svelte

@@ -1,16 +1,24 @@
 <script lang="ts">
 <script lang="ts">
-	import { createEventDispatcher, onMount } from 'svelte';
+	import { createEventDispatcher, onDestroy, onMount } from 'svelte';
 	const dispatch = createEventDispatcher();
 	const dispatch = createEventDispatcher();
 
 
 	let loaderElement: HTMLElement;
 	let loaderElement: HTMLElement;
 
 
+	let observer;
+	let intervalId;
+
 	onMount(() => {
 	onMount(() => {
-		const observer = new IntersectionObserver(
+		observer = new IntersectionObserver(
 			(entries, observer) => {
 			(entries, observer) => {
 				entries.forEach((entry) => {
 				entries.forEach((entry) => {
 					if (entry.isIntersecting) {
 					if (entry.isIntersecting) {
-						dispatch('visible');
+						intervalId = setInterval(() => {
+							dispatch('visible');
+						}, 100);
+						// dispatch('visible');
 						// observer.unobserve(loaderElement); // Stop observing until content is loaded
 						// observer.unobserve(loaderElement); // Stop observing until content is loaded
+					} else {
+						clearInterval(intervalId);
 					}
 					}
 				});
 				});
 			},
 			},
@@ -23,6 +31,14 @@
 
 
 		observer.observe(loaderElement);
 		observer.observe(loaderElement);
 	});
 	});
+
+	onDestroy(() => {
+		observer.disconnect();
+
+		if (intervalId) {
+			clearInterval(intervalId);
+		}
+	});
 </script>
 </script>
 
 
 <div bind:this={loaderElement}>
 <div bind:this={loaderElement}>