fix: transitions

Use Vuetify transition classes and add new `enter` and `leave` hooks for
further transition customization.
This commit is contained in:
Fernando Fernández
2023-04-03 12:52:57 +02:00
parent cfa6d2ec56
commit 64f0a42b03
9 changed files with 55 additions and 117 deletions
@@ -1,61 +0,0 @@
/* Default transitions */
.page-enter-active,
.layout-enter-active {
animation: enter-page 0.2s;
}
.page-leave-active,
.layout-leave-active {
animation: leave-page 0.2s;
}
@media (prefers-reduced-motion) {
.page-enter-active,
.layout-enter-active {
transition: none !important;
animation: none !important;
}
}
@keyframes enter-page {
0% {
opacity: 0;
transform: translate3d(10px, 0, 0);
}
100% {
opacity: 1;
transform: initial;
}
}
@keyframes leave-page {
0% {
opacity: 1;
transform: initial;
}
100% {
opacity: 0;
transform: translate3d(-10px, 0, 0);
}
}
/* Slide-up transition */
.slideUp-enter-active,
.slideUp-leave-active {
animation: slideUp-enter 0.2s;
}
@keyframes slideUp-enter {
0% {
opacity: 0;
transform: initial;
}
100% {
opacity: 1;
transform: translate3d(0, -100%, 0);
}
}
@@ -1,33 +1,28 @@
<template>
<router-view v-if="enableTransitions" v-slot="{ Component, route }">
<transition :name="route.meta.transition || 'page'" mode="out-in">
<router-view v-slot="{ Component, route }">
<transition
:name="!prefersNoMotion ? getTransitionName(route) : undefined"
mode="out-in"
@before-enter="(el: HTMLElement) => el.style.transformOrigin = 'center center'">
<!-- This div is required because <transition> requires a single children node -->
<div
:key="getKey(route)"
class="h-100"
:class="
isRoot
? 'router-view-root-transition-wrapper'
: 'router-view-transition-wrapper'
">
<div :key="isRoot ? route.meta.layout : String(route.name)" class="h-100">
<Suspense>
<component :is="Component" />
</Suspense>
</div>
</transition>
</router-view>
<router-view v-else v-slot="{ Component }">
<Suspense>
<component :is="Component" />
</Suspense>
</router-view>
</template>
<script setup lang="ts">
import { RouteLocationNormalized } from 'vue-router';
<script lang="ts">
import { RouteLocationNormalizedLoaded } from 'vue-router';
import { useMediaQuery } from '@vueuse/core';
interface Props {
const prefersNoMotion = useMediaQuery('(prefers-reduced-motion)');
</script>
<script setup lang="ts">
defineProps<{
/**
* Root transitions happen between layout changes. e.g. from `default` layout to `main` and viceversa.
* This should be "true" for the App.vue component
@@ -35,22 +30,18 @@ interface Props {
* layout
*/
isRoot?: boolean;
enableTransitions?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
isRoot: false,
enableTransitions: true
});
}>();
/**
* Gets the key to re-render the component tree of the current page
* Get transition name
*/
function getKey(route: RouteLocationNormalized): string {
if (props.isRoot) {
return route.meta.layout;
function getTransitionName(
route: RouteLocationNormalizedLoaded
): undefined | string {
if (route.meta.transition?.enter) {
return route.meta.transition.enter;
}
return String(route.name);
return 'scroll-x-reverse-transition';
}
</script>
-1
View File
@@ -20,7 +20,6 @@ import { hideDirective } from '@/plugins/directives';
* - GLOBAL STYLES -
*/
import '@/assets/styles/global.scss';
import '@/assets/styles/transitions.scss';
/**
* - VUE PLUGINS, STORE AND DIRECTIVE -
-4
View File
@@ -170,10 +170,6 @@ const homeSections = computed<HomeSection[]>(() => {
</script>
<style lang="scss" scoped>
.top-carousel {
margin-top: -64px;
}
.sections-after-header {
position: relative;
z-index: 4;
+3 -1
View File
@@ -70,7 +70,9 @@ meta:
layout: fullpage
backdrop:
opacity: 0.75
transition: slideUp
transition:
enter: 'scroll-y-reverse-transition'
leave: 'scroll-y-transition'
</route>
<script setup lang="ts">
+3 -1
View File
@@ -112,7 +112,9 @@
<route lang="yaml">
meta:
layout: fullpage
transition: slideUp
transition:
enter: 'scroll-y-reverse-transition'
leave: 'scroll-y-transition'
</route>
<script lang="ts" setup>
@@ -15,26 +15,22 @@ const routes = new Set([serverAddUrl, serverSelectUrl, serverLoginUrl]);
* Redirects to login page if there's no user logged in.
*/
export default function loginGuard(
to?: RouteLocationNormalized
to: RouteLocationNormalized
): boolean | RouteLocationRaw {
const remote = useRemote();
let destinationRoute: RouteLocationPathRaw | undefined;
if (to) {
if (remote.auth.servers.length <= 0) {
destinationRoute = { path: serverAddUrl, replace: true };
} else if (!routes.has(to.path)) {
if (isNil(remote.auth.currentServer)) {
destinationRoute = { path: serverSelectUrl, replace: true };
} else if (isNil(remote.auth.currentUser)) {
destinationRoute = { path: serverLoginUrl, replace: true };
}
if (remote.auth.servers.length <= 0) {
destinationRoute = { path: serverAddUrl, replace: true };
} else if (!routes.has(to.path)) {
if (isNil(remote.auth.currentServer)) {
destinationRoute = { path: serverSelectUrl, replace: true };
} else if (isNil(remote.auth.currentUser)) {
destinationRoute = { path: serverLoginUrl, replace: true };
}
return destinationRoute && to.path !== destinationRoute.path
? destinationRoute
: true;
} else {
return false;
}
return destinationRoute && to.path !== destinationRoute.path
? destinationRoute
: true;
}
@@ -38,9 +38,18 @@ const defaultMeta: RouteMeta = {
* present at the plugins.d.ts file
*/
export default function metaGuard(
to: RouteLocationNormalized
to: RouteLocationNormalized,
from: RouteLocationNormalized
): boolean | RouteLocationRaw {
to.meta = reactive<RouteMeta>(defaultsDeep(to.meta, defaultMeta));
if (from.meta.transition?.leave) {
if (!to.meta.transition) {
to.meta.transition = { enter: from.meta.transition.leave };
} else {
to.meta.transition.enter = from.meta.transition.leave;
}
}
return true;
}
+5 -1
View File
@@ -12,11 +12,15 @@ interface BackdropPayload {
blurhash?: string;
opacity?: number;
}
interface RouteTransition {
enter: string;
leave?: string;
}
declare module 'vue-router' {
interface RouteMeta {
readonly layout: string;
transparentLayout?: boolean;
transition?: string;
transition?: RouteTransition;
readonly admin: boolean;
title?: string | null;
backdrop: BackdropPayload;