fix: replace legacy timeouts with v-bind in navtab component (#5343)

* fix: dont use timeouts for navtabs

* fix: remove nexttick
This commit is contained in:
Calum H.
2026-02-09 15:24:39 +00:00
committed by GitHub
parent e80d7730ca
commit dd4b054d95

View File

@@ -55,7 +55,7 @@
<script setup lang="ts">
import type { Component } from 'vue'
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import { computed, onMounted, ref, watch } from 'vue'
const route = useNativeRoute()
@@ -104,6 +104,9 @@ const subpageSelected = ref(false)
const sliderReady = ref(false) // Slider is positioned and should be visible
const transitionsEnabled = ref(false) // CSS transitions should apply (after first paint)
// Stagger delays for the trailing edges of the slider animation
const sliderDelays = ref({ left: '0ms', top: '0ms', right: '0ms', bottom: '0ms' })
const filteredLinks = computed(() => props.links.filter((link) => link.shown ?? true))
const sliderStyle = computed(() => ({
@@ -114,6 +117,11 @@ const sliderStyle = computed(() => ({
opacity: sliderReady.value && currentActiveIndex.value !== -1 ? 1 : 0,
}))
const leftDelay = computed(() => sliderDelays.value.left)
const rightDelay = computed(() => sliderDelays.value.right)
const topDelay = computed(() => sliderDelays.value.top)
const bottomDelay = computed(() => sliderDelays.value.bottom)
const isActiveAndNotSubpage = computed(
() => (index: number) => currentActiveIndex.value === index && !subpageSelected.value,
)
@@ -229,25 +237,20 @@ function animateSliderTo(newPosition: {
right: number
bottom: number
}) {
const STAGGER_DELAY = 200
const STAGGER_DELAY = '200ms'
// Horizontal animation - lead with the direction of movement
if (newPosition.left < sliderLeft.value) {
sliderLeft.value = newPosition.left
setTimeout(() => (sliderRight.value = newPosition.right), STAGGER_DELAY)
} else {
sliderRight.value = newPosition.right
setTimeout(() => (sliderLeft.value = newPosition.left), STAGGER_DELAY)
// Set stagger delays: leading edge moves immediately, trailing edge is delayed
sliderDelays.value = {
left: newPosition.left < sliderLeft.value ? '0ms' : STAGGER_DELAY,
right: newPosition.left < sliderLeft.value ? STAGGER_DELAY : '0ms',
top: newPosition.top < sliderTop.value ? '0ms' : STAGGER_DELAY,
bottom: newPosition.top < sliderTop.value ? STAGGER_DELAY : '0ms',
}
// Vertical animation - lead with the direction of movement
if (newPosition.top < sliderTop.value) {
sliderTop.value = newPosition.top
setTimeout(() => (sliderBottom.value = newPosition.bottom), STAGGER_DELAY)
} else {
sliderBottom.value = newPosition.bottom
setTimeout(() => (sliderTop.value = newPosition.top), STAGGER_DELAY)
}
sliderLeft.value = newPosition.left
sliderRight.value = newPosition.right
sliderTop.value = newPosition.top
sliderBottom.value = newPosition.bottom
}
function updateActiveTab() {
@@ -256,7 +259,7 @@ function updateActiveTab() {
subpageSelected.value = isSubpage
if (index !== -1) {
nextTick(positionSlider)
positionSlider()
} else {
sliderLeft.value = 0
sliderRight.value = 0
@@ -293,7 +296,10 @@ watch(() => props.links, updateActiveTab, { deep: true })
<style scoped>
.navtabs-transition {
transition:
all 150ms cubic-bezier(0.4, 0, 0.2, 1),
left 150ms cubic-bezier(0.4, 0, 0.2, 1) v-bind(leftDelay),
right 150ms cubic-bezier(0.4, 0, 0.2, 1) v-bind(rightDelay),
top 150ms cubic-bezier(0.4, 0, 0.2, 1) v-bind(topDelay),
bottom 150ms cubic-bezier(0.4, 0, 0.2, 1) v-bind(bottomDelay),
opacity 250ms cubic-bezier(0.5, 0, 0.2, 1) 50ms;
}