feat(ui-transitions): more transitions
Signed-off-by: Neko Ayaka <neko@ayaka.moe>
This commit is contained in:
@@ -5,7 +5,9 @@ import Buttons from '../components/Buttons.vue'
|
||||
|
||||
definePage({
|
||||
meta: {
|
||||
stageTransition: 'slide',
|
||||
stageTransition: {
|
||||
name: 'slide',
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,9 @@ import Buttons from '../components/Buttons.vue'
|
||||
|
||||
definePage({
|
||||
meta: {
|
||||
stageTransition: 'slope-slide',
|
||||
stageTransition: {
|
||||
name: 'slope-slide',
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,9 @@ import Buttons from '../components/Buttons.vue'
|
||||
|
||||
definePage({
|
||||
meta: {
|
||||
stageTransition: 'arrow',
|
||||
stageTransition: {
|
||||
name: 'arrow',
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,9 @@ import Buttons from '../components/Buttons.vue'
|
||||
|
||||
definePage({
|
||||
meta: {
|
||||
stageTransition: 'multiple-blocks-reveal',
|
||||
stageTransition: {
|
||||
name: 'multiple-blocks-reveal',
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,9 @@ import Buttons from '../components/Buttons.vue'
|
||||
|
||||
definePage({
|
||||
meta: {
|
||||
stageTransition: 'fantasy-fall',
|
||||
stageTransition: {
|
||||
name: 'fantasy-fall',
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,9 @@ import Buttons from '../components/Buttons.vue'
|
||||
|
||||
definePage({
|
||||
meta: {
|
||||
stageTransition: 'rectangles-rotate',
|
||||
stageTransition: {
|
||||
name: 'rectangles-rotate',
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,9 @@ import Buttons from '../components/Buttons.vue'
|
||||
|
||||
definePage({
|
||||
meta: {
|
||||
stageTransition: 'bubble-wave-out',
|
||||
stageTransition: {
|
||||
name: 'bubble-wave-out',
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -2,15 +2,20 @@
|
||||
import { computed, onMounted } from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
primaryColor?: string
|
||||
secondaryColor?: string
|
||||
stageTransition?: {
|
||||
primaryColor?: string
|
||||
secondaryColor?: string
|
||||
}
|
||||
}>(), {
|
||||
primaryColor: '#666',
|
||||
secondaryColor: '#ccc',
|
||||
stageTransition: () => ({
|
||||
primaryColor: '#666',
|
||||
secondaryColor: '#ccc',
|
||||
}),
|
||||
})
|
||||
|
||||
const overlayColor1 = computed(() => props.primaryColor || '#666')
|
||||
const overlayColor2 = computed(() => props.secondaryColor || '#ccc')
|
||||
const stageTransition = computed(() => props.stageTransition)
|
||||
const overlayColor1 = computed(() => stageTransition.value.primaryColor || '#666')
|
||||
const overlayColor2 = computed(() => stageTransition.value.secondaryColor || '#ccc')
|
||||
|
||||
onMounted(() => {
|
||||
document.documentElement.style.setProperty('--stage-transition-3-overlay-color-1', overlayColor1.value)
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue'
|
||||
import { computed, onMounted } from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
colors?: string[]
|
||||
delay?: number
|
||||
duration?: number
|
||||
}>(), {
|
||||
colors: () => ['#eee', '#ebcb8b', '#c56370', '#3f3b52'],
|
||||
delay: 0,
|
||||
duration: 0.4,
|
||||
})
|
||||
const props = defineProps<{
|
||||
stageTransition?: {
|
||||
colors?: string[]
|
||||
delay?: number
|
||||
duration?: number
|
||||
}
|
||||
}>()
|
||||
|
||||
const colors = computed(() => props.stageTransition.colors || ['#eee', '#ebcb8b', '#c56370', '#3f3b52'])
|
||||
|
||||
onMounted(() => {
|
||||
document.documentElement.style.setProperty('--circle-expansion-delay', `${props.delay}s`)
|
||||
document.documentElement.style.setProperty('--circle-expansion-duration', `${props.duration}s`)
|
||||
props.colors.forEach((color, index) => {
|
||||
document.documentElement.style.setProperty('--circle-expansion-delay', `${props.stageTransition.delay || 0}s`)
|
||||
document.documentElement.style.setProperty('--circle-expansion-duration', `${props.stageTransition.duration || 0.4}s`)
|
||||
colors.value.forEach((color, index) => {
|
||||
document.documentElement.style.setProperty(`--circle-expansion-color-${index + 1}`, color)
|
||||
})
|
||||
})
|
||||
@@ -22,7 +22,7 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div class="circle-expansion-transition">
|
||||
<div v-for="(_, index) in props.colors" :key="index" />
|
||||
<div v-for="(_, index) in colors" :key="index" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,33 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
primaryColor?: string
|
||||
duration?: number
|
||||
delay?: number
|
||||
borderRadius?: {
|
||||
sm?: string
|
||||
md?: string
|
||||
lg?: string
|
||||
const props = defineProps <{
|
||||
stageTransition?: {
|
||||
primaryColor?: string
|
||||
duration?: number
|
||||
delay?: number
|
||||
borderRadius?: {
|
||||
sm?: string
|
||||
md?: string
|
||||
lg?: string
|
||||
}
|
||||
}
|
||||
}>(), {
|
||||
primaryColor: '#eee',
|
||||
duration: 0.6,
|
||||
delay: 0,
|
||||
borderRadius: () => ({
|
||||
sm: '14rem',
|
||||
md: '14rem',
|
||||
lg: '50%',
|
||||
}),
|
||||
})
|
||||
}> ()
|
||||
|
||||
onMounted(() => {
|
||||
document.documentElement.style.setProperty('--fantasy-fall-color', props.primaryColor)
|
||||
document.documentElement.style.setProperty('--fantasy-fall-duration', `${props.duration}s`)
|
||||
document.documentElement.style.setProperty('--fantasy-fall-delay', `${props.delay}s`)
|
||||
document.documentElement.style.setProperty('--fantasy-fall-radius-sm', `${props.borderRadius.sm}`)
|
||||
document.documentElement.style.setProperty('--fantasy-fall-radius-md', `${props.borderRadius.md}`)
|
||||
document.documentElement.style.setProperty('--fantasy-fall-radius-lg', `${props.borderRadius.lg}`)
|
||||
document.documentElement.style.setProperty('--fantasy-fall-color', props.stageTransition.primaryColor || '#eee')
|
||||
document.documentElement.style.setProperty('--fantasy-fall-duration', `${props.stageTransition.duration || 0.6}s`)
|
||||
document.documentElement.style.setProperty('--fantasy-fall-delay', `${props.stageTransition.delay || 0}s`)
|
||||
document.documentElement.style.setProperty('--fantasy-fall-radius-sm', `${props.stageTransition.borderRadius?.sm || '14rem'}`)
|
||||
document.documentElement.style.setProperty('--fantasy-fall-radius-md', `${props.stageTransition.borderRadius?.md || '14rem'}`)
|
||||
document.documentElement.style.setProperty('--fantasy-fall-radius-lg', `${props.stageTransition.borderRadius?.lg || '50%'}`)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,15 +2,20 @@
|
||||
import { computed, onMounted } from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
primaryColor?: string
|
||||
secondaryColor?: string
|
||||
stageTransition?: {
|
||||
primaryColor?: string
|
||||
secondaryColor?: string
|
||||
}
|
||||
}>(), {
|
||||
primaryColor: '#666',
|
||||
secondaryColor: '#ccc',
|
||||
stageTransition: () => ({
|
||||
primaryColor: '#666',
|
||||
secondaryColor: '#ccc',
|
||||
}),
|
||||
})
|
||||
|
||||
const overlayColor1 = computed(() => props.primaryColor || '#666')
|
||||
const overlayColor2 = computed(() => props.secondaryColor || '#ccc')
|
||||
const stageTransition = computed(() => props.stageTransition)
|
||||
const overlayColor1 = computed(() => stageTransition.value.primaryColor || '#666')
|
||||
const overlayColor2 = computed(() => stageTransition.value.secondaryColor || '#ccc')
|
||||
|
||||
onMounted(() => {
|
||||
document.documentElement.style.setProperty('--stage-transition-4-overlay-color-1', overlayColor1.value)
|
||||
|
||||
@@ -1,33 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
primaryColor?: string
|
||||
secondaryColor?: string
|
||||
tertiaryColor?: string
|
||||
duration?: number
|
||||
delay?: number
|
||||
rotation?: number
|
||||
staggerDelay?: number
|
||||
}>(), {
|
||||
primaryColor: '#ebcb8b', // First circle (top-left)
|
||||
secondaryColor: '#c56370', // Second circle (bottom-right)
|
||||
tertiaryColor: '#43445b', // Third circle (center)
|
||||
duration: 0.6,
|
||||
delay: 0,
|
||||
rotation: 270,
|
||||
staggerDelay: 0.1, // Delay between each circle animation
|
||||
})
|
||||
const props = defineProps<{
|
||||
stageTransition?: {
|
||||
primaryColor?: string
|
||||
secondaryColor?: string
|
||||
tertiaryColor?: string
|
||||
duration?: number
|
||||
delay?: number
|
||||
rotation?: number
|
||||
staggerDelay?: number
|
||||
}
|
||||
}>()
|
||||
|
||||
onMounted(() => {
|
||||
// Set CSS variables for all three circles
|
||||
document.documentElement.style.setProperty('--rectangle-rotate-1-color', props.primaryColor)
|
||||
document.documentElement.style.setProperty('--rectangle-rotate-2-color', props.secondaryColor)
|
||||
document.documentElement.style.setProperty('--rectangle-rotate-3-color', props.tertiaryColor)
|
||||
document.documentElement.style.setProperty('--rectangle-rotate-duration', `${props.duration}s`)
|
||||
document.documentElement.style.setProperty('--rectangle-rotate-delay', `${props.delay}s`)
|
||||
document.documentElement.style.setProperty('--rectangle-rotate-stagger', `${props.staggerDelay}s`)
|
||||
document.documentElement.style.setProperty('--rectangle-rotate-rotation', `${props.rotation}deg`)
|
||||
document.documentElement.style.setProperty('--rectangle-rotate-1-color', props.stageTransition.primaryColor || '#ebcb8b')
|
||||
document.documentElement.style.setProperty('--rectangle-rotate-2-color', props.stageTransition.secondaryColor || '#c56370')
|
||||
document.documentElement.style.setProperty('--rectangle-rotate-3-color', props.stageTransition.tertiaryColor || '#43445b')
|
||||
document.documentElement.style.setProperty('--rectangle-rotate-duration', `${props.stageTransition.duration || 0.6}s`)
|
||||
document.documentElement.style.setProperty('--rectangle-rotate-delay', `${props.stageTransition.delay || 0}s`)
|
||||
document.documentElement.style.setProperty('--rectangle-rotate-stagger', `${props.stageTransition.staggerDelay || 0.1}s`)
|
||||
document.documentElement.style.setProperty('--rectangle-rotate-rotation', `${props.stageTransition.rotation || 270}deg`)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,15 +2,20 @@
|
||||
import { computed, onMounted } from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
primaryColor?: string
|
||||
secondaryColor?: string
|
||||
stageTransition?: {
|
||||
primaryColor?: string
|
||||
secondaryColor?: string
|
||||
}
|
||||
}>(), {
|
||||
primaryColor: '#666',
|
||||
secondaryColor: '#ccc',
|
||||
stageTransition: () => ({
|
||||
primaryColor: '#666',
|
||||
secondaryColor: '#ccc',
|
||||
}),
|
||||
})
|
||||
|
||||
const overlayColor1 = computed(() => props.primaryColor || '#666')
|
||||
const overlayColor2 = computed(() => props.secondaryColor || '#ccc')
|
||||
const stageTransition = computed(() => props.stageTransition)
|
||||
const overlayColor1 = computed(() => stageTransition.value.primaryColor || '#666')
|
||||
const overlayColor2 = computed(() => stageTransition.value.secondaryColor || '#ccc')
|
||||
|
||||
onMounted(() => {
|
||||
document.documentElement.style.setProperty('--stage-transition-1-overlay-color-1', overlayColor1.value)
|
||||
|
||||
@@ -2,15 +2,20 @@
|
||||
import { computed, onMounted } from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
primaryColor?: string
|
||||
secondaryColor?: string
|
||||
stageTransition?: {
|
||||
primaryColor?: string
|
||||
secondaryColor?: string
|
||||
}
|
||||
}>(), {
|
||||
primaryColor: '#666',
|
||||
secondaryColor: '#ccc',
|
||||
stageTransition: () => ({
|
||||
primaryColor: '#666',
|
||||
secondaryColor: '#ccc',
|
||||
}),
|
||||
})
|
||||
|
||||
const overlayColor1 = computed(() => props.primaryColor || '#666')
|
||||
const overlayColor2 = computed(() => props.secondaryColor || '#ccc')
|
||||
const stageTransition = computed(() => props.stageTransition)
|
||||
const overlayColor1 = computed(() => stageTransition.value.primaryColor || '#666')
|
||||
const overlayColor2 = computed(() => stageTransition.value.secondaryColor || '#ccc')
|
||||
|
||||
onMounted(() => {
|
||||
document.documentElement.style.setProperty('--stage-transition-2-overlay-color-1', overlayColor1.value)
|
||||
|
||||
@@ -10,13 +10,17 @@ import RectanglesRotateTransition from './RectanglesRotateTransition.vue'
|
||||
import SlideTransition from './SlideTransition.vue'
|
||||
import SlopeSlideTransition from './SlopeSlideTransition.vue'
|
||||
|
||||
withDefaults(defineProps<{
|
||||
const props = defineProps<{
|
||||
primaryColor?: string
|
||||
secondaryColor?: string
|
||||
}>(), {
|
||||
primaryColor: '#666',
|
||||
secondaryColor: '#ccc',
|
||||
})
|
||||
}>()
|
||||
|
||||
interface StageTransitionCommonParams {
|
||||
name: string
|
||||
primaryColor?: string
|
||||
secondaryColor?: string
|
||||
direction?: 'top' | 'bottom' | 'left' | 'right'
|
||||
}
|
||||
|
||||
type TransitionComponent =
|
||||
| typeof SlideTransition
|
||||
@@ -29,8 +33,10 @@ type TransitionComponent =
|
||||
|
||||
const router = useRouter()
|
||||
const showTransition = ref(false)
|
||||
const transitionStage = ref<TransitionStage>()
|
||||
|
||||
const activeTransitionName = ref('')
|
||||
const transitionStage = ref<TransitionStage | null>(null)
|
||||
const activeStageTransitionParams = ref<StageTransitionCommonParams>()
|
||||
|
||||
// Define transition lifecycle events
|
||||
export type TransitionStage =
|
||||
@@ -115,10 +121,10 @@ async function triggerHooks(stage: TransitionStage, data: any = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
async function triggerTransitionAsyncFn(name: string, next: NavigationCallback, resolve: (value: void | PromiseLike<void>) => void) {
|
||||
const transition = transitions.value[name]
|
||||
async function triggerTransitionAsyncFn(params: StageTransitionCommonParams, next: NavigationCallback, resolve: (value: void | PromiseLike<void>) => void) {
|
||||
const transition = transitions.value[params.name]
|
||||
if (!transition) {
|
||||
console.error(`Transition ${name} not found`)
|
||||
console.error(`Transition ${params.name} not found`)
|
||||
next()
|
||||
resolve()
|
||||
return
|
||||
@@ -144,13 +150,14 @@ async function triggerTransitionAsyncFn(name: string, next: NavigationCallback,
|
||||
|
||||
try {
|
||||
// Before enter
|
||||
await triggerHooks('before-enter', { transitionName: name })
|
||||
await triggerHooks('before-enter', { transitionName: params.name })
|
||||
|
||||
// Handle resetting current transition if needed
|
||||
if (showTransition.value) {
|
||||
// Fast track to exit if a transition is already active
|
||||
await triggerHooks('before-leave', { transitionName: activeTransitionName.value })
|
||||
activeTransitionName.value = ''
|
||||
activeStageTransitionParams.value = undefined
|
||||
showTransition.value = false
|
||||
await triggerHooks('after-leave', { transitionName: activeTransitionName.value })
|
||||
|
||||
@@ -159,7 +166,8 @@ async function triggerTransitionAsyncFn(name: string, next: NavigationCallback,
|
||||
}
|
||||
|
||||
// Start new transition
|
||||
activeTransitionName.value = name
|
||||
activeTransitionName.value = params.name
|
||||
activeStageTransitionParams.value = params
|
||||
showTransition.value = true
|
||||
|
||||
// Enter active phase
|
||||
@@ -167,10 +175,7 @@ async function triggerTransitionAsyncFn(name: string, next: NavigationCallback,
|
||||
|
||||
// Trigger navigation phase at the configured time
|
||||
setTimeout(async () => {
|
||||
await triggerHooks('navigation', {
|
||||
transitionName: name,
|
||||
config: transition, // Pass full config to hooks
|
||||
})
|
||||
await triggerHooks('navigation', { transitionName: params.name, config: transition })
|
||||
|
||||
// Ensure navigation happens even if no hook handled it
|
||||
if (!hasNavigated) {
|
||||
@@ -181,17 +186,17 @@ async function triggerTransitionAsyncFn(name: string, next: NavigationCallback,
|
||||
|
||||
// After enter - entry phase complete
|
||||
setTimeout(async () => {
|
||||
await triggerHooks('after-enter', { transitionName: name })
|
||||
await triggerHooks('after-enter', { transitionName: params.name })
|
||||
}, transition.duration)
|
||||
|
||||
// Before leave - start exit phase
|
||||
setTimeout(async () => {
|
||||
await triggerHooks('before-leave', { transitionName: name })
|
||||
await triggerHooks('before-leave', { transitionName: params.name })
|
||||
}, transition.duration + 10) // Small offset after enter completes
|
||||
|
||||
// Leave active - exit animation running
|
||||
setTimeout(async () => {
|
||||
await triggerHooks('leave-active', { transitionName: name })
|
||||
await triggerHooks('leave-active', { transitionName: params.name })
|
||||
}, transition.duration + 20) // Small offset
|
||||
|
||||
// After leave - completely finished
|
||||
@@ -199,10 +204,14 @@ async function triggerTransitionAsyncFn(name: string, next: NavigationCallback,
|
||||
setTimeout(async () => {
|
||||
showTransition.value = false
|
||||
activeTransitionName.value = ''
|
||||
await triggerHooks('after-leave', { transitionName: name })
|
||||
activeStageTransitionParams.value = undefined
|
||||
await triggerHooks('after-leave', { transitionName: params.name })
|
||||
resolve()
|
||||
}, transition.duration + totalDuration)
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
finally {
|
||||
// Always remove the navigation hook
|
||||
removeNavHook()
|
||||
@@ -218,14 +227,27 @@ async function triggerTransitionAsyncFn(name: string, next: NavigationCallback,
|
||||
}
|
||||
|
||||
// Improved transition trigger with navigation callback
|
||||
function triggerTransition(name: string, next: NavigationCallback) {
|
||||
function triggerTransition(params: StageTransitionCommonParams, next: NavigationCallback) {
|
||||
return new Promise<void>((resolve) => {
|
||||
triggerTransitionAsyncFn(name, next, resolve)
|
||||
triggerTransitionAsyncFn(params, next, resolve)
|
||||
})
|
||||
}
|
||||
|
||||
router.beforeEach((to, _from, next) => {
|
||||
triggerTransition(to.meta.stageTransition as string, next)
|
||||
if (typeof to.meta.stageTransition !== 'object') {
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
const stageTransition = to.meta.stageTransition as StageTransitionCommonParams
|
||||
if (typeof props.primaryColor !== 'undefined') {
|
||||
stageTransition.primaryColor = props.primaryColor
|
||||
}
|
||||
if (typeof props.secondaryColor !== 'undefined') {
|
||||
stageTransition.secondaryColor = props.secondaryColor
|
||||
}
|
||||
|
||||
triggerTransition(stageTransition, next)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -233,7 +255,7 @@ router.beforeEach((to, _from, next) => {
|
||||
<slot />
|
||||
<template v-if="showTransition">
|
||||
<template v-if="transitions[activeTransitionName]">
|
||||
<component :is="transitions[activeTransitionName].component" :primary-color="primaryColor" :secondary-color="secondaryColor" />
|
||||
<component :is="transitions[activeTransitionName].component" :stage-transition="activeStageTransitionParams" />
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user