feat: add better provider support, icons, regen, and a lot more

This commit is contained in:
Zoe
2026-02-12 14:56:13 +00:00
parent d5a5945c03
commit d29f95bacf
124 changed files with 6374 additions and 1861 deletions
+33 -15
View File
@@ -1,53 +1,68 @@
import { ref, watch, onUnmounted, type Ref } from 'vue';
export function useAutoScroll(elementRef: Ref<HTMLElement | null>) {
const userIsScrollingUp = ref(false);
const THRESHOLD = 50;
export function useAutoScroll(elementRef: Ref<HTMLElement | null>, options: {
threshold?: number;
} = {}) {
const { threshold = 80 } = options;
const isAtBottom = () => {
const el = elementRef.value;
if (!el) return false;
const distanceToBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
return distanceToBottom <= THRESHOLD;
};
const isUserScrollingUp = ref(false);
const shouldAutoScroll = ref(true);
const scrollToBottom = (behavior: ScrollBehavior = 'auto') => {
const scrollToBottom = (behavior: ScrollBehavior = 'smooth') => {
const el = elementRef.value;
if (!el) return;
el.scrollTo({
top: el.scrollHeight,
behavior,
});
shouldAutoScroll.value = true;
};
const handleScroll = () => {
const el = elementRef.value;
if (!el) return;
userIsScrollingUp.value = !isAtBottom();
const { scrollTop, scrollHeight, clientHeight } = el;
const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
if (distanceFromBottom <= threshold) {
if (isUserScrollingUp.value) {
isUserScrollingUp.value = false;
shouldAutoScroll.value = true;
}
} else {
isUserScrollingUp.value = true;
shouldAutoScroll.value = false;
}
};
let observer: MutationObserver | null = null;
let timeout: NodeJS.Timeout | null = null;
watch(elementRef, (newEl, oldEl) => {
if (oldEl) {
oldEl.removeEventListener('scroll', handleScroll);
observer?.disconnect();
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
}
if (newEl) {
newEl.addEventListener('scroll', handleScroll, { passive: true });
observer = new MutationObserver(() => {
if (!userIsScrollingUp.value) {
scrollToBottom();
// Only auto-scroll if user hasn't scrolled up and is near bottom
if (!isUserScrollingUp.value && shouldAutoScroll.value) {
scrollToBottom('instant');
}
});
observer.observe(newEl, {
childList: true,
subtree: true,
characterData: true
characterData: true,
});
}
});
@@ -55,10 +70,13 @@ export function useAutoScroll(elementRef: Ref<HTMLElement | null>) {
onUnmounted(() => {
elementRef.value?.removeEventListener('scroll', handleScroll);
observer?.disconnect();
if (timeout) {
clearTimeout(timeout);
}
});
return {
userIsScrollingUp,
scrollToBottom,
isUserScrollingUp, // expose for UI feedback (optional)
};
}