Merge branch 'virtual-scrolling-2.0' into shigusegubu-themes3

This commit is contained in:
Henry Jameson 2026-09-09 19:42:07 +03:00
commit 048e8e88fb
4 changed files with 48 additions and 31 deletions

View file

@ -1,14 +1,6 @@
import { get } from 'lodash-es' import { get } from 'lodash-es'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { import { computed, provide, ref, toRefs, useTemplateRef, watch } from 'vue'
computed,
nextTick,
provide,
ref,
toRefs,
useTemplateRef,
watch,
} from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import ChatMessageList from 'src/components/chat_message_list/chat_message_list.vue' import ChatMessageList from 'src/components/chat_message_list/chat_message_list.vue'
@ -24,9 +16,9 @@ import { useStatusesStore } from 'src/stores/statuses.js'
import { useStreamingStore } from 'src/stores/streaming.js' import { useStreamingStore } from 'src/stores/streaming.js'
import { useConversation } from 'src/composables/useConversation.js' import { useConversation } from 'src/composables/useConversation.js'
import { useScrollPosition } from 'src/composables/useScrollPosition.js'
import { useTreeConversationTopology } from 'src/composables/useTreeConversationTopology.js' import { useTreeConversationTopology } from 'src/composables/useTreeConversationTopology.js'
import { useVirtualScrolling } from 'src/composables/useVirtualScrolling.js' import { useVirtualScrolling } from 'src/composables/useVirtualScrolling.js'
import { useScrollPosition } from 'src/composables/useScrollPosition.js'
import { WSConnectionStatus } from 'src/api/websocket.js' import { WSConnectionStatus } from 'src/api/websocket.js'
@ -147,15 +139,19 @@ export default {
loadError, loadError,
} = useConversation(focusedId, isExpanded) } = useConversation(focusedId, isExpanded)
watch(expanded, async (value) => { watch(
if (value) { expanded,
await fetchConversation() async (value) => {
} else { if (value) {
resetDisplayState() await fetchConversation()
} } else {
if (isPage.value) return resetDisplayState()
await tryScrollTo(currentStatus.value.id) }
}, { flush: 'post' }) if (isPage.value) return
await tryScrollTo(currentStatus.value.id)
},
{ flush: 'post' },
)
const resetDisplayState = () => { const resetDisplayState = () => {
setFocused(statusId.value) setFocused(statusId.value)
@ -194,12 +190,20 @@ export default {
// # Linear style stuff // # Linear style stuff
const isLinearView = computed(() => displayStyle.value !== 'tree') const isLinearView = computed(() => displayStyle.value !== 'tree')
const linearElement = useTemplateRef('linear') const linearElement = useTemplateRef('linear')
const linearScrollCompensation = computed(() => isLinearView.value && isExpanded.value) const linearScrollCompensation = computed(
() => isLinearView.value && isExpanded.value,
)
const { const {
heightChart: heightChartLinear, heightChart: heightChartLinear,
changeSuspendState: changeSuspendStateLinear, changeSuspendState: changeSuspendStateLinear,
updateVirtualHeight: updateVirtualHeightLinear, updateVirtualHeight: updateVirtualHeightLinear,
} = useVirtualScrolling(conversation, linearElement, scroller, linearScrollCompensation, currentStatus) } = useVirtualScrolling(
conversation,
linearElement,
scroller,
linearScrollCompensation,
currentStatus,
)
// # Tree style stuff // # Tree style stuff
const isTreeView = computed(() => displayStyle.value === 'tree') const isTreeView = computed(() => displayStyle.value === 'tree')
@ -213,18 +217,24 @@ export default {
provide('threadDisplay', threadDisplay) provide('threadDisplay', threadDisplay)
const ancestorsElement = useTemplateRef('ancestors') const ancestorsElement = useTemplateRef('ancestors')
const treeScrollCompensation = computed(() => isTreeView.value && isExpanded.value) const treeScrollCompensation = computed(
() => isTreeView.value && isExpanded.value,
)
const { const {
heightChart: heightChartAncestors, heightChart: heightChartAncestors,
changeSuspendState: changeSuspendStateAncestors, changeSuspendState: changeSuspendStateAncestors,
updateVirtualHeight: updateVirtualHeightAncestors, updateVirtualHeight: updateVirtualHeightAncestors,
} = useVirtualScrolling(currentAncestors, ancestorsElement, scroller, treeScrollCompensation) } = useVirtualScrolling(
currentAncestors,
ancestorsElement,
scroller,
treeScrollCompensation,
)
const currentLevel = computed(() => [currentStatus.value].filter(Boolean)) const currentLevel = computed(() => [currentStatus.value].filter(Boolean))
const currentLevelElement = useTemplateRef('currentLevel') const currentLevelElement = useTemplateRef('currentLevel')
const { const {
heightChart: heightChartCurrentLevel, heightChart: heightChartCurrentLevel,
totalHeight: totalHeightCurrentLevel,
changeSuspendState: changeSuspendStateCurrentLevel, changeSuspendState: changeSuspendStateCurrentLevel,
updateVirtualHeight: updateVirtualHeightCurrentLevel, updateVirtualHeight: updateVirtualHeightCurrentLevel,
} = useVirtualScrolling(currentLevel, currentLevelElement, scroller, false) } = useVirtualScrolling(currentLevel, currentLevelElement, scroller, false)

View file

@ -149,7 +149,10 @@ const Status = {
computed: { computed: {
rootClasses() { rootClasses() {
return [ return [
{'-focused': this.focused, '-conversation': !this.isPage && this.isExpanded }, {
'-focused': this.focused,
'-conversation': !this.isPage && this.isExpanded,
},
`-conversation-rank-${this.conversationRank}`, `-conversation-rank-${this.conversationRank}`,
] ]
}, },

View file

@ -1,4 +1,4 @@
import { onMounted, onUnmounted, ref, nextTick } from 'vue' import { onMounted, onUnmounted, ref } from 'vue'
export function useScrollPosition() { export function useScrollPosition() {
const x = ref(0) const x = ref(0)

View file

@ -1,5 +1,5 @@
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { computed, ref, watch, nextTick, toValue } from 'vue' import { computed, ref, toValue, watch } from 'vue'
import { useMergedConfigStore } from 'src/stores/merged_config.js' import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useStatusesStore } from 'src/stores/statuses.js' import { useStatusesStore } from 'src/stores/statuses.js'
@ -133,9 +133,10 @@ export function useVirtualScrolling(
if (!toValue(scrollCompensation)) return if (!toValue(scrollCompensation)) return
if (scrollInProgress.value) return if (scrollInProgress.value) return
pauseWatchers() pauseWatchers()
const getAnchoredEl = (list) => anchor.value const getAnchoredEl = (list) =>
? list.find(({ id }) => id === anchor.value) anchor.value
: list[list.length - 1] ? list.find(({ id }) => id === anchor.value)
: list[list.length - 1]
const oldElement = getAnchoredEl(oldVal) const oldElement = getAnchoredEl(oldVal)
const newElement = getAnchoredEl(newVal) const newElement = getAnchoredEl(newVal)
const oldOffset = oldElement?.top ?? 0 const oldOffset = oldElement?.top ?? 0
@ -169,7 +170,10 @@ export function useVirtualScrolling(
const isAboveBottomBoundary = itemTopBoundary < finalBottomScrollBoundary const isAboveBottomBoundary = itemTopBoundary < finalBottomScrollBoundary
// This accounts for the case where item's boundaries exceed scroll boundary // This accounts for the case where item's boundaries exceed scroll boundary
return { ...heightChartItem, visible: isBelowTopBoundary && isAboveBottomBoundary } return {
...heightChartItem,
visible: isBelowTopBoundary && isAboveBottomBoundary,
}
}) })
// Group invisible statuses into spacers // Group invisible statuses into spacers