Skip to content

Commit

Permalink
Feature - Scroll to Previous Message (#1440)
Browse files Browse the repository at this point in the history
* Added "Scroll to Previous Message" button.

* update mobile positioning to 50%

* fix linting issues in ScrollToPreviousBtn

---------

Co-authored-by: Nathan Sarrazin <[email protected]>
  • Loading branch information
evalstate and nsarrazin authored Sep 27, 2024
1 parent 3f659ae commit d60cfa3
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 1 deletion.
70 changes: 70 additions & 0 deletions src/lib/components/ScrollToPreviousBtn.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<script lang="ts">
import { fade } from "svelte/transition";
import { onDestroy } from "svelte";
import IconChevron from "./icons/IconChevron.svelte";
export let scrollNode: HTMLElement;
export { className as class };
let visible = false;
let className = "";
let observer: ResizeObserver | null = null;
$: if (scrollNode) {
destroy();
if (window.ResizeObserver) {
observer = new ResizeObserver(() => {
updateVisibility();
});
observer.observe(scrollNode);
}
scrollNode.addEventListener("scroll", updateVisibility);
}
function updateVisibility() {
if (!scrollNode) return;
visible =
Math.ceil(scrollNode.scrollTop) + 200 < scrollNode.scrollHeight - scrollNode.clientHeight &&
scrollNode.scrollTop > 200;
}
function scrollToPrevious() {
if (!scrollNode) return;
const messages = scrollNode.querySelectorAll('[id^="message-"]');
const scrollTop = scrollNode.scrollTop;
let previousMessage: Element | null = null;
for (let i = messages.length - 1; i >= 0; i--) {
const messageTop =
messages[i].getBoundingClientRect().top +
scrollTop -
scrollNode.getBoundingClientRect().top;
if (messageTop < scrollTop - 1) {
previousMessage = messages[i];
break;
}
}
if (previousMessage) {
previousMessage.scrollIntoView({ behavior: "smooth", block: "start" });
}
}
function destroy() {
observer?.disconnect();
scrollNode?.removeEventListener("scroll", updateVisibility);
}
onDestroy(destroy);
</script>

{#if visible}
<button
transition:fade={{ duration: 150 }}
on:click={scrollToPrevious}
class="btn absolute flex h-[41px] w-[41px] rounded-full border bg-white shadow-md transition-all hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-700 dark:shadow-gray-950 dark:hover:bg-gray-600 {className}"
>
<IconChevron classNames="rotate-180 mt-[2px]" />
</button>
{/if}
2 changes: 2 additions & 0 deletions src/lib/components/chat/ChatMessage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
{#if message.from === "assistant"}
<div
class="group relative -mb-4 flex items-start justify-start gap-4 pb-4 leading-relaxed"
id="message-assistant-{message.id}"
role="presentation"
on:click={() => (isTapped = !isTapped)}
on:keydown={() => (isTapped = !isTapped)}
Expand Down Expand Up @@ -372,6 +373,7 @@
{#if message.from === "user"}
<div
class="group relative w-full items-start justify-start gap-4 max-sm:text-sm"
id="message-user-{message.id}"
role="presentation"
on:click={() => (isTapped = !isTapped)}
on:keydown={() => (isTapped = !isTapped)}
Expand Down
9 changes: 8 additions & 1 deletion src/lib/components/chat/ChatWindow.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import AssistantIntroduction from "./AssistantIntroduction.svelte";
import ChatMessage from "./ChatMessage.svelte";
import ScrollToBottomBtn from "../ScrollToBottomBtn.svelte";
import ScrollToPreviousBtn from "../ScrollToPreviousBtn.svelte";
import { browser } from "$app/environment";
import { snapScrollToBottom } from "$lib/actions/snapScrollToBottom";
import SystemPromptModal from "../SystemPromptModal.svelte";
Expand Down Expand Up @@ -328,8 +329,14 @@
/>
{/if}
</div>

<ScrollToPreviousBtn
class="fixed right-4 max-md:bottom-[calc(50%+26px)] md:bottom-48 lg:right-10"
scrollNode={chatContainer}
/>

<ScrollToBottomBtn
class="bottom-36 right-4 max-md:hidden lg:right-10"
class="fixed right-4 max-md:bottom-[calc(50%-26px)] md:bottom-36 lg:right-10"
scrollNode={chatContainer}
/>
</div>
Expand Down

0 comments on commit d60cfa3

Please sign in to comment.