Skip to content

Commit

Permalink
Use smooth scrolling for chatbox (#27)
Browse files Browse the repository at this point in the history
* Use smooth scrolling for chatbox

* Check correct direction LULE

* Added standard setting component slider

* Added setting to controll smooth scroll
  • Loading branch information
Excellify authored Jan 9, 2023
1 parent 0cb084c commit 3f7406b
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 7 deletions.
2 changes: 1 addition & 1 deletion src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ declare namespace SevenTV {
type SettingType = boolean | number | string | object;

namespace SettingNode {
type ComponentType = "SELECT" | "DROPDOWN" | "CHECKBOX" | "INPUT" | "TOGGLE" | "CUSTOM";
type ComponentType = "SELECT" | "DROPDOWN" | "CHECKBOX" | "INPUT" | "TOGGLE" | "SLIDER" | "CUSTOM";
}

interface ActiveEmote {
Expand Down
43 changes: 37 additions & 6 deletions src/site/twitch.tv/ChatAPI.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Ref, computed, nextTick, reactive, ref, toRefs, watchEffect } from "vue";
import { useStore } from "@/store/main";
import { useConfig } from "@/composable/useSettings";
import UiScrollableVue from "@/ui/UiScrollable.vue";

const scrollduration = useConfig<number>("chat.smooth_scroll_duration");

const data = reactive({
// Message Data
messages: [] as Twitch.ChatMessage[],
Expand Down Expand Up @@ -36,7 +39,12 @@ const data = reactive({
sys: true,
visible: true,
paused: false, // whether or not scrolling is paused
duration: scrollduration,

scrollBuffer: [] as Twitch.ChatMessage[], // twitch chat message buffe when scrolling is paused
scrollClear: () => {
return;
},

// Functions
sendMessage: (() => {
Expand Down Expand Up @@ -111,7 +119,7 @@ export function useChatAPI(scroller?: Ref<InstanceType<typeof UiScrollableVue> |
}
}

nextTick(() => scrollToLive());
nextTick(() => scrollToLive(data.duration));

flushTimeout = undefined;
}, 25);
Expand All @@ -121,14 +129,35 @@ export function useChatAPI(scroller?: Ref<InstanceType<typeof UiScrollableVue> |
/**
* Scrolls the chat to the bottom
*/
function scrollToLive(): void {
function scrollToLive(duration = 0): void {
if (!container.value || !bounds?.value || data.paused) return;

data.scrollClear();

data.sys = true;

container.value.scrollTo({ top: container.value.scrollHeight });
const from = container.value.scrollTop;
const start = Date.now();

let shouldClear = false;

function scroll() {
if (!container.value || !bounds?.value || data.paused || shouldClear) return;

const currentTime = Date.now();
const time = Math.min(1, (currentTime - start) / duration);
container.value.scrollTop = time * (container.value.scrollHeight - from) + from;

if (time < 1) requestAnimationFrame(scroll);
else bounds.value = container.value.getBoundingClientRect();
}

data.scrollClear = () => (shouldClear = true);

bounds.value = container.value.getBoundingClientRect();
if (duration < 1) {
container.value.scrollTo({ top: container.value.scrollHeight });
bounds.value = container.value.getBoundingClientRect();
} else requestAnimationFrame(scroll);
}

/**
Expand Down Expand Up @@ -182,8 +211,8 @@ export function useChatAPI(scroller?: Ref<InstanceType<typeof UiScrollableVue> |
}
}

function onWheel() {
data.userInput++;
function onWheel(e: WheelEvent) {
if (e.deltaY < 0) data.userInput++;
}

const {
Expand All @@ -199,6 +228,7 @@ export function useChatAPI(scroller?: Ref<InstanceType<typeof UiScrollableVue> |
init,
scrollBuffer,
paused,
duration,
isModerator,
isVIP,
sendMessage,
Expand All @@ -223,6 +253,7 @@ export function useChatAPI(scroller?: Ref<InstanceType<typeof UiScrollableVue> |
scrollInit: init,
scrollBuffer: scrollBuffer,
scrollPaused: paused,
scrollDuration: duration,

sendMessage,
clear,
Expand Down
8 changes: 8 additions & 0 deletions src/site/twitch.tv/modules/chat/ChatModule.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ const { dependenciesMet, markAsReady } = useModule("chat", {
options: ["Show", "Blur"],
defaultValue: false,
},
{
key: "chat.smooth_scroll_duration",
label: "Smooth scroll chat",
hint: "How smooth should the chat scroll on new messages. 0 is instant",
type: "SLIDER",
options: [0, 3000, "ms"],
defaultValue: 0,
},
],
});
Expand Down
24 changes: 24 additions & 0 deletions src/site/twitch.tv/modules/settings/components/Slider.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<template>
<div>
<input
:id="node.key"
v-model="setting"
type="range"
:min="(node.options?.at(0) as number)"
:max="(node.options?.at(1) as number)"
class="slider"
/>
{{ setting }}
{{ node.options?.at(2) }}
</div>
</template>

<script setup lang="ts">
import { useConfig } from "@/composable/useSettings";
const props = defineProps<{
node: SevenTV.SettingNode<number>;
}>();
const setting = useConfig<number>(props.node.key);
</script>
2 changes: 2 additions & 0 deletions src/site/twitch.tv/modules/settings/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Checkbox from "./Checkbox.vue";
import Dropdown from "./Dropdown.vue";
import Input from "./Input.vue";
import Select from "./Select.vue";
import Slider from "./Slider.vue";
import Toggle from "./Toggle.vue";

const standard = {
Expand All @@ -10,6 +11,7 @@ const standard = {
CHECKBOX: Checkbox,
INPUT: Input,
TOGGLE: Toggle,
SLIDER: Slider,
CUSTOM: undefined,
};

Expand Down

0 comments on commit 3f7406b

Please sign in to comment.