diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 316a33bb7..b77ead529 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -19,6 +19,7 @@ import { useConversation } from 'src/composables/useConversation.js' import { useScrollPosition } from 'src/composables/useScrollPosition.js' import { useTreeConversationTopology } from 'src/composables/useTreeConversationTopology.js' import { useVirtualScrolling } from 'src/composables/useVirtualScrolling.js' +import { useInterfaceSizes } from 'src/composables/useInterfaceSizes.js' import { WSConnectionStatus } from 'src/api/websocket.js' @@ -83,7 +84,7 @@ export default { } setFocused(id) const target = document.querySelector(`.Status[data-status-id=${id}]`) - return await scroller.scrollIntoView(target, { block: 'start' }) + return await scroller.scrollIntoView(target, { block: 'nearest' }) } const { statusId } = toRefs(props) @@ -148,7 +149,6 @@ export default { resetDisplayState() } if (isPage.value) return - await tryScrollTo(currentStatus.value.id) }, { flush: 'post' }, ) @@ -187,18 +187,7 @@ export default { '-last': status.id === lastStatus.value?.id, }) - // Getting the actual font size in pixels since UI might have - // a different scale - const fontSizeSetting = computed(() => mergedConfig.value.textSize) - const fontSize = ref(0) - const updateFontSize = () => { - const string = window - .getComputedStyle(document.body) - .getPropertyValue('font-size') - fontSize.value = Number.parseInt(string.slice(0, -2), 10) // remove the 'px' - } - // Update font size if user changed UI scale - watch(fontSizeSetting, updateFontSize, { immediate: true }) + const { fontSize } = useInterfaceSizes() // Placeholder heights. const mutedStatusHeight = computed(() => fontSize.value * 1.5) @@ -218,6 +207,8 @@ export default { heightChart: heightChartLinear, changeSuspendState: changeSuspendStateLinear, updateVirtualHeight: updateVirtualHeightLinear, + pauseWatchers, + resumeWatchers, } = useVirtualScrolling({ list: conversation, body: linearElement, @@ -227,6 +218,16 @@ export default { getPlaceholderHeight, }) + watch( + expanded, + async (value) => { + pauseWatchers() + await tryScrollTo(currentStatus.value.id) + resumeWatchers() + }, + { flush: 'post' }, + ) + // # Tree style stuff const isTreeView = computed(() => displayStyle.value === 'tree') const { diff --git a/src/composables/useInterfaceSizes.js b/src/composables/useInterfaceSizes.js new file mode 100644 index 000000000..43bc79be1 --- /dev/null +++ b/src/composables/useInterfaceSizes.js @@ -0,0 +1,43 @@ +import { computed, ref, toValue, watch } from 'vue' +import { storeToRefs } from 'pinia' + +import { useMergedConfigStore } from 'src/stores/merged_config.js' + +export function useInterfaceSizes() { + const { mergedConfig } = storeToRefs(useMergedConfigStore()) + + // Getting the actual font size in pixels since UI might have + // a different scale + const fontSizeSetting = computed(() => mergedConfig.value.textSize) + const fontSize = ref(0) + const updateFontSize = () => { + const string = window + .getComputedStyle(document.body) + .getPropertyValue('font-size') + fontSize.value = Number.parseInt(string.slice(0, -2), 10) // remove the 'px' + } + // Update font size if user changed UI scale + watch(fontSizeSetting, updateFontSize, { immediate: true }) + + const navbarSize = computed(() => { + const string = fontSize.value * window + .getComputedStyle(document.body) + .getPropertyValue('--navbarSize') + + return fontSize.value * Number.parseInt(string.slice(0, -3), 10) // remove the 'rem' + }) + + const panelHeaderSize = computed(() => { + const string = fontSize.value * window + .getComputedStyle(document.body) + .getPropertyValue('--panelHeaderSize') + + return fontSize.value * Number.parseInt(string.slice(0, -3), 10) // remove the 'rem' + }) + + return { + fontSize, + navbarSize, + panelHeaderSize, + } +} diff --git a/src/composables/useScrollPosition.js b/src/composables/useScrollPosition.js index 6a5e43b18..1cf337314 100644 --- a/src/composables/useScrollPosition.js +++ b/src/composables/useScrollPosition.js @@ -1,5 +1,7 @@ import { onMounted, onUnmounted, ref } from 'vue' +import { useWindowSize } from 'src/composables/useWindowSize.js' + export function useScrollPosition() { const x = ref(0) const y = ref(0) @@ -25,8 +27,24 @@ export function useScrollPosition() { } const scrollIntoView = async (element, options) => { + if (element == null) throw new TypeError(`Element is ${element}!`) inProgress.value = true - await element.scrollIntoViewIfNeeded(options) + let call = element.scrollIntoViewIfNeeded + if (!call) { + call = (options) => { + const { height: windowHeight } = useWindowSize() + const { top, height } = element.getBoundingClientRect() + const bottom = top + height + + const biggerThanScreen = height > windowHeight + const aboveTop = top < 0 + const belowBottom = bottom > windowHeight.value + if (aboveTop || belowBottom || biggerThanScreen) { + element.scrollIntoView(options) + } + } + } + await call(options) inProgress.value = false }