waffle/frontend/src/components/pages/main/Messages.svelte

88 lines
2.6 KiB
Svelte
Raw Normal View History

<script>
2022-04-20 17:49:31 +03:00
import { afterUpdate, beforeUpdate } from "svelte";
import { messagesStoreProvider } from "../../../stores.js";
export let channelId;
2022-04-20 17:49:31 +03:00
let scrollTarget;
let shouldAutoscroll = false;
let lastScrollHeight = null;
$: messages = messagesStoreProvider.getStore(channelId);
2022-04-20 17:49:31 +03:00
beforeUpdate(() => {
shouldAutoscroll = scrollTarget && (scrollTarget.offsetHeight + scrollTarget.scrollTop) > (scrollTarget.scrollHeight - 20);
});
afterUpdate(() => {
// hacky way to preserve scroll position when messages are pushed back
if (lastScrollHeight) {
scrollTarget.scrollTop = scrollTarget.scrollHeight - lastScrollHeight;
lastScrollHeight = null;
return;
}
2022-04-20 17:49:31 +03:00
if (shouldAutoscroll && scrollTarget) {
scrollTarget.scrollTo(0, scrollTarget.scrollHeight);
2022-04-20 17:49:31 +03:00
}
});
const onScroll = (e) => {
const { scrollTop, offsetHeight, scrollHeight } = e.target;
if ((scrollTop + offsetHeight) >= scrollHeight) { // user scrolled to bottom
messages.setIsCollectingOldMessages(true);
} else {
if (scrollTop === 0) {
// load older messages if the user scrolls to the top.
// save the current scroll height if the server returned any messages,
// before commiting them to the store. this is to provide the jank scroll height
// preservation
messages.loadOlderMessages(() => {
if (scrollTarget)
lastScrollHeight = scrollTarget.scrollHeight;
});
}
messages.setIsCollectingOldMessages(false);
}
};
</script>
<style>
.messages-container {
padding: var(--space-normplus);
2022-04-22 23:01:44 +03:00
padding-bottom: 0;
height: 100%;
width: 100%;
flex-grow: 0;
overflow-y: auto;
2022-04-22 23:01:44 +03:00
overflow-x: hidden;
background-color: var(--background-color-1);
}
2022-04-22 23:01:44 +03:00
.message {
overflow-x: none;
word-break: break-all;
}
.message-content {
color: var(--foreground-color-2);
}
2022-04-22 23:01:44 +03:00
.pending {
color: var(--foreground-color-3);
}
.author {
font-weight: bold;
margin-right: var(--space-xxs);
}
</style>
<div class="messages-container" on:scroll={ onScroll } bind:this={ scrollTarget }>
{#each $messages as message (message.id)}
2022-04-22 23:01:44 +03:00
<div class="message">
<span class="author">{ message.author_username }</span>
<span class="message-content" class:pending={ message._isPending }>{ message.content }</span>
</div>
{/each}
</div>