♻️ refactor: optimize state management, switch to @tanstack/vue-virtual, and improve performance
- Centralize `useAgents` and `useModels` state within the Nuxt app context to prevent data leaks and improve initialization. - Migrate virtualization from `vue-virtual-scroller` to `@tanstack/vue-virtual` with new `RowVirtualizerFixed` and `RowVirtualizerDynamic` components. - Upgrade Nuxt to v4.3.1 and remove `@vue-macros/nuxt`. - Replace `big.js` with an optimized custom `lshDecimal` string manipulation logic for pricing calculations in the provider API. - Implement automatic focus redirection in `ChatInput` to capture standard keyboard input. - Refactor Sidenav and Settings components to utilize virtualization for long lists (topics, agents, models). - Enhance theme colors and mobile experience. More work to come on both of these.
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
<script setup lang="ts">
|
||||
import { useVirtualizer } from '@tanstack/vue-virtual';
|
||||
|
||||
const props = defineProps<{
|
||||
items: any[];
|
||||
keyField?: string;
|
||||
scrollElement: HTMLElement | null;
|
||||
minItemSize: number;
|
||||
overscan: number;
|
||||
prerender?: number;
|
||||
}>();
|
||||
|
||||
const rowVirtualizer = useVirtualizer(computed(() => ({
|
||||
count: props.items.length,
|
||||
getScrollElement: () => props.scrollElement,
|
||||
estimateSize: () => props.minItemSize,
|
||||
overscan: props.overscan,
|
||||
getItemKey: (index: number) => props.keyField ? props.items[index]?.[props.keyField] || index : index,
|
||||
initialRect: {
|
||||
width: 0,
|
||||
height: props.prerender ? props.minItemSize * props.prerender : 0
|
||||
},
|
||||
})));
|
||||
|
||||
const virtualRows = computed(() => rowVirtualizer.value.getVirtualItems());
|
||||
const totalSize = computed(() => rowVirtualizer.value.getTotalSize());
|
||||
|
||||
const measureElement = (el: Element) => {
|
||||
if (!el) {
|
||||
return
|
||||
}
|
||||
|
||||
rowVirtualizer.value.measureElement(el)
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
watch(() => props.items, () => {
|
||||
rowVirtualizer.value.measure();
|
||||
}, { deep: false });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :style="{ height: `${totalSize}px`, width: '100%', position: 'relative' }">
|
||||
<div v-for="virtualRow in virtualRows" :ref="(el) => measureElement(el as Element)"
|
||||
:key="(virtualRow.key as any | number)" :data-index="virtualRow.index" :style="{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: `${virtualRow.size}`,
|
||||
transform: `translateY(${virtualRow.start}px)`,
|
||||
}">
|
||||
<slot :item="props.items[virtualRow.index]" :index="virtualRow.index" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user