more scrolling shenanigans

This commit is contained in:
Henry Jameson 2026-09-09 18:57:15 +03:00
commit d622a61fd1
3 changed files with 29 additions and 17 deletions

View file

@ -26,6 +26,7 @@ import { useStreamingStore } from 'src/stores/streaming.js'
import { useConversation } from 'src/composables/useConversation.js' import { useConversation } from 'src/composables/useConversation.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'
@ -90,12 +91,13 @@ export default {
setFocused(id) setFocused(id)
const target = document.querySelector(`.Status[data-status-id=${id}]`) const target = document.querySelector(`.Status[data-status-id=${id}]`)
await nextTick() await nextTick()
target.scrollIntoView({ behavior: 'smooth', block: 'center' }) return await target.scrollIntoView({ behavior: 'smooth', block: 'center' })
} }
const { statusId } = toRefs(props) const { statusId } = toRefs(props)
const router = useRouter() const router = useRouter()
const scroller = useScrollPosition()
// # Main Configuration / global state // # Main Configuration / global state
const { mergedConfig } = storeToRefs(useMergedConfigStore()) const { mergedConfig } = storeToRefs(useMergedConfigStore())
@ -146,10 +148,10 @@ export default {
loadError, loadError,
} = useConversation(focusedId, isExpanded) } = useConversation(focusedId, isExpanded)
watch(expanded, (value) => { watch(expanded, async (value) => {
tryScrollTo(currentStatus.value.id)
if (value) { if (value) {
fetchConversation() await fetchConversation()
await tryScrollTo(currentStatus.value.id)
} else { } else {
resetDisplayState() resetDisplayState()
} }
@ -196,7 +198,7 @@ export default {
heightChart: heightChartLinear, heightChart: heightChartLinear,
changeSuspendState: changeSuspendStateLinear, changeSuspendState: changeSuspendStateLinear,
updateVirtualHeight: updateVirtualHeightLinear, updateVirtualHeight: updateVirtualHeightLinear,
} = useVirtualScrolling(conversation, linearElement, currentStatus) } = useVirtualScrolling(conversation, linearElement, scroller, true, currentStatus)
// # Tree style stuff // # Tree style stuff
const isTreeView = computed(() => displayStyle.value === 'tree') const isTreeView = computed(() => displayStyle.value === 'tree')
@ -214,7 +216,7 @@ export default {
heightChart: heightChartAncestors, heightChart: heightChartAncestors,
changeSuspendState: changeSuspendStateAncestors, changeSuspendState: changeSuspendStateAncestors,
updateVirtualHeight: updateVirtualHeightAncestors, updateVirtualHeight: updateVirtualHeightAncestors,
} = useVirtualScrolling(currentAncestors, ancestorsElement) } = useVirtualScrolling(currentAncestors, ancestorsElement, scroller, true)
const currentLevel = computed(() => [currentStatus.value].filter(Boolean)) const currentLevel = computed(() => [currentStatus.value].filter(Boolean))
const currentLevelElement = useTemplateRef('currentLevel') const currentLevelElement = useTemplateRef('currentLevel')
@ -223,7 +225,7 @@ export default {
totalHeight: totalHeightCurrentLevel, totalHeight: totalHeightCurrentLevel,
changeSuspendState: changeSuspendStateCurrentLevel, changeSuspendState: changeSuspendStateCurrentLevel,
updateVirtualHeight: updateVirtualHeightCurrentLevel, updateVirtualHeight: updateVirtualHeightCurrentLevel,
} = useVirtualScrolling(currentLevel, currentLevelElement, currentStatus) } = useVirtualScrolling(currentLevel, currentLevelElement, scroller, false)
const treeViewIsSimple = computed( const treeViewIsSimple = computed(
() => !mergedConfig.value.conversationTreeAdvanced, () => !mergedConfig.value.conversationTreeAdvanced,
@ -239,12 +241,8 @@ export default {
) )
// # Scrolling // # Scrolling
const diveIntoStatus = (id) => { const diveIntoStatus = (id) => tryScrollTo(id)
tryScrollTo(id) const diveToTopLevel = () => tryScrollTo(currentAncestors.value[0].id)
}
const diveToTopLevel = () => {
tryScrollTo(currentAncestors.value[0].id)
}
return { return {
// # Misc // # Misc

View file

@ -3,6 +3,7 @@ import { onMounted, onUnmounted, ref } from 'vue'
export function useScrollPosition() { export function useScrollPosition() {
const x = ref(0) const x = ref(0)
const y = ref(0) const y = ref(0)
const inProgress = ref(false)
const update = (e) => { const update = (e) => {
x.value = window.scrollX x.value = window.scrollX
@ -17,5 +18,11 @@ export function useScrollPosition() {
window.removeEventListener('scroll', update) window.removeEventListener('scroll', update)
}) })
return { x, y } const scrollBy = async (x1, y1, options) => {
inProgress.value = true
await window.scrollBy(x1, y1, options)
inProgress.value = false
}
return { x, y, scrollBy, inProgress }
} }

View file

@ -4,10 +4,15 @@ import { computed, ref, watch, nextTick } 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'
import { useScrollPosition } from 'src/composables/useScrollPosition.js'
import { useWindowSize } from 'src/composables/useWindowSize.js' import { useWindowSize } from 'src/composables/useWindowSize.js'
export function useVirtualScrolling(conversation, body, anchorStatus) { export function useVirtualScrolling(
conversation,
body,
scrollPosition,
scrollCompensation,
anchorStatus,
) {
const getStatusObject = (id) => useStatusesStore().allStatuses.get(id) const getStatusObject = (id) => useStatusesStore().allStatuses.get(id)
const { mergedConfig } = storeToRefs(useMergedConfigStore()) const { mergedConfig } = storeToRefs(useMergedConfigStore())
@ -64,7 +69,7 @@ export function useVirtualScrolling(conversation, body, anchorStatus) {
} }
// Scrolling // Scrolling
const { y: scrollY } = useScrollPosition() const { y: scrollY, inProgress: scrollInProgress } = scrollPosition
const { height: windowHeight } = useWindowSize() const { height: windowHeight } = useWindowSize()
const topScrollBoundary = ref(0) const topScrollBoundary = ref(0)
@ -125,6 +130,8 @@ export function useVirtualScrolling(conversation, body, anchorStatus) {
}) })
watch(heightChart, async (newVal, oldVal) => { watch(heightChart, async (newVal, oldVal) => {
if (scrollInProgress) return
if (!scrollCompensation) return
pauseWatchers() pauseWatchers()
const getAnchoredEl = (list) => anchor.value const getAnchoredEl = (list) => anchor.value
? list.find(({ id }) => id === anchor.value) ? list.find(({ id }) => id === anchor.value)