File size: 2,019 Bytes
8aab1a5
98051f8
 
 
ef7aeda
feb88db
98051f8
 
ef7aeda
01b06a3
 
ef7aeda
 
8aab1a5
 
949cae0
 
01b06a3
 
 
8aab1a5
 
feb88db
 
 
 
 
 
 
4a396c5
feb88db
 
8aab1a5
 
45dbaaf
6a0861b
070d5c7
45dbaaf
 
6a0861b
949cae0
ef7aeda
 
 
f16c630
ef7aeda
 
8aab1a5
01b06a3
 
 
8aab1a5
949cae0
f16c630
 
 
 
949cae0
8aab1a5
 
45dbaaf
6a0861b
45dbaaf
 
8aab1a5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<script lang="ts">
	import type { Message } from "$lib/types/Message";
	import { snapScrollToBottom } from "$lib/actions/snapScrollToBottom";
	import ScrollToBottomBtn from "$lib/components/ScrollToBottomBtn.svelte";
	import { createEventDispatcher, tick } from "svelte";

	import ChatIntroduction from "./ChatIntroduction.svelte";
	import ChatMessage from "./ChatMessage.svelte";
	import { randomUUID } from "$lib/utils/randomUuid";
	import type { Model } from "$lib/types/Model";
	import type { LayoutData } from "../../../routes/$types";

	const dispatch = createEventDispatcher<{ retry: { id: Message["id"]; content: string } }>();

	export let messages: Message[];
	export let loading: boolean;
	export let pending: boolean;
	export let currentModel: Model;
	export let settings: LayoutData["settings"];
	export let models: Model[] | undefined;

	let chatContainer: HTMLElement;

	async function scrollToBottom() {
		await tick();
		chatContainer.scrollTop = chatContainer.scrollHeight;
	}

	// If last message is from user, scroll to bottom
	$: if (messages[messages.length - 1]?.from === "user") {
		scrollToBottom();
	}
</script>

<div
	class="scrollbar-custom mr-1 h-full overflow-y-auto"
	use:snapScrollToBottom={messages.length ? messages : false}
	bind:this={chatContainer}
>
	<div class="mx-auto flex h-full max-w-3xl flex-col gap-5 px-5 pt-6 sm:gap-8 xl:max-w-4xl">
		{#each messages as message, i}
			<ChatMessage
				loading={loading && i === messages.length - 1}
				{message}
				model={currentModel}
				on:retry={() => dispatch("retry", { id: message.id, content: message.content })}
			/>
		{:else}
			{#if models}
				<ChatIntroduction {settings} {models} {currentModel} on:message />
			{/if}
		{/each}
		{#if pending}
			<ChatMessage
				message={{ from: "assistant", content: "", id: randomUUID() }}
				model={currentModel}
			/>
		{/if}
		<div class="h-32 flex-none" />
	</div>
	<ScrollToBottomBtn
		class="bottom-36 right-4 max-md:hidden lg:right-10"
		scrollNode={chatContainer}
	/>
</div>