Просмотр исходного кода

Feature: Mobile - Added mobile transition for route changes.

Dominik Klein 3 лет назад
Родитель
Сommit
5a27246257

+ 0 - 1
.eslintrc.js

@@ -19,7 +19,6 @@ module.exports = {
     'plugin:jest/recommended',
     '@vue/prettier',
     '@vue/typescript/recommended',
-    '@vue/prettier/@typescript-eslint',
     'prettier',
   ],
   rules: {

+ 2 - 1
.stylelintrc.json

@@ -46,6 +46,7 @@
     "**/fineuploader.css",
     "**/qunit*.css",
     "**/svg-dimensions.css",
-    "vendor/**"
+    "vendor/**",
+    "coverage/**"
   ]
 }

+ 1 - 5
app/frontend/apps/mobile/App.vue

@@ -5,11 +5,7 @@
   <div
     class="min-h-screen min-w-screen bg-dark text-gray-400 text-center text-sm antialiased font-sans select-none"
   >
-    <router-view v-if="applicationLoaded.value" v-slot="{ Component }">
-      <transition>
-        <component v-bind:is="Component" />
-      </transition>
-    </router-view>
+    <router-view v-if="applicationLoaded.value" />
   </div>
 </template>
 

+ 18 - 3
app/frontend/apps/mobile/components/layout/LayoutMain.vue

@@ -4,13 +4,28 @@
   <div class="flex flex-col h-screen overflow-hidden">
     <main class="flex-1 overflow-y-scroll">
       <router-view v-slot="{ Component }">
-        <transition>
+        <TransitionViewNavigation>
           <component v-bind:is="Component" />
-        </transition>
+        </TransitionViewNavigation>
       </router-view>
     </main>
-    <footer class="w-full bg-darker text-center border-t p-4">
+    <footer
+      v-if="showBottomNavigation"
+      class="w-full bg-darker text-center border-t p-4"
+    >
       Bottom-Navigation
     </footer>
   </div>
 </template>
+
+<script setup lang="ts">
+import { computed } from 'vue'
+import { useRoute } from 'vue-router'
+import TransitionViewNavigation from '@mobile/components/transition/TransitionViewNavigation.vue'
+
+const route = useRoute()
+
+const showBottomNavigation = computed(() => {
+  return route.meta.hasBottomNavigation
+})
+</script>

+ 96 - 0
app/frontend/apps/mobile/components/transition/TransitionViewNavigation.vue

@@ -0,0 +1,96 @@
+<!-- Copyright (C) 2012-2021 Zammad Foundation, https://zammad-foundation.org/ -->
+
+<template>
+  <main class="min-h-screen grid flex-1 overflow-hidden">
+    <transition class="flex-auto z-10" v-bind:name="viewTransition">
+      <slot></slot>
+    </transition>
+  </main>
+</template>
+
+<script setup lang="ts">
+import useViewTransition from '@mobile/composables/useViewTransition'
+
+const { viewTransition } = useViewTransition()
+</script>
+
+<style scoped>
+/* TODO: Styles needs to be aligned/beautified. */
+
+/* Example from: https://codesandbox.io/s/zq5mw2zk9x */
+main {
+  grid-template: 'main';
+}
+
+main > * {
+  grid-area: main; /* Transition: make sections overlap on same cell */
+}
+
+/* next */
+
+.next-leave-to {
+  animation: leaveToLeft 300ms both cubic-bezier(0.19, 0.61, 0.44, 1);
+  z-index: 0;
+}
+
+.next-enter-to {
+  animation: enterFromRight 400ms both cubic-bezier(0.19, 0.61, 0.44, 1);
+  z-index: 1;
+}
+
+@keyframes leaveToLeft {
+  from {
+    transform: translateX(0);
+  }
+
+  to {
+    transform: translateX(-25%);
+    filter: brightness(0.4);
+  }
+}
+
+@keyframes enterFromRight {
+  from {
+    transform: translateX(100%);
+  }
+
+  to {
+    transform: translateX(0);
+  }
+}
+
+/* prev */
+
+.prev-leave-to {
+  animation: leaveToRight 400ms both cubic-bezier(0.19, 0.61, 0.44, 1);
+  z-index: 1;
+}
+
+.prev-enter-to {
+  animation: enterFromLeft 300ms both cubic-bezier(0.19, 0.61, 0.44, 1);
+  z-index: 0;
+}
+
+@keyframes enterFromLeft {
+  from {
+    transform: translateX(-25%);
+    filter: brightness(0.5);
+  }
+
+  to {
+    transform: translateX(0);
+  }
+}
+
+@keyframes leaveToRight {
+  from {
+    transform: translateX(0);
+    filter: brightness(0.9);
+  }
+
+  to {
+    transform: translateX(100%);
+    filter: brightness(0.8);
+  }
+}
+</style>

+ 17 - 0
app/frontend/apps/mobile/composables/useViewTransition.ts

@@ -0,0 +1,17 @@
+// Copyright (C) 2012-2021 Zammad Foundation, https://zammad-foundation.org/
+
+import { ViewTransitions } from '@mobile/types/transition'
+import { ref } from 'vue'
+
+const viewTransition = ref<ViewTransitions>(ViewTransitions.REPLACE)
+
+export default function useViewTransition() {
+  function setViewTransition(newViewTransition: ViewTransitions) {
+    viewTransition.value = newViewTransition
+  }
+
+  return {
+    setViewTransition,
+    viewTransition,
+  }
+}

+ 5 - 1
app/frontend/apps/mobile/main.ts

@@ -20,6 +20,7 @@ import useLocaleStore from '@common/stores/locale'
 import useSessionUserStore from '@common/stores/session/user'
 import useAuthenticatedStore from '@common/stores/authenticated'
 import 'virtual:svg-icons-register' // eslint-disable-line import/no-unresolved
+import transitionViewGuard from '@mobile/router/guards/before/viewTransition'
 
 const enableLoadingAnimation = (): void => {
   const loadingElement: Maybe<HTMLElement> =
@@ -40,7 +41,10 @@ export default async function mountApp(): Promise<void> {
   provideApolloClient(apolloClient)
 
   initializeStore(app)
-  initializeRouter(app, routes)
+  const router = initializeRouter(app, routes)
+
+  // Add app custom specific guards.
+  router.beforeEach(transitionViewGuard)
 
   initializeGlobalComponents(app)
 

+ 39 - 0
app/frontend/apps/mobile/router/guards/before/viewTransition.ts

@@ -0,0 +1,39 @@
+// Copyright (C) 2012-2021 Zammad Foundation, https://zammad-foundation.org/
+
+import useViewTransition from '@mobile/composables/useViewTransition'
+import { ViewTransitions } from '@mobile/types/transition'
+import type {
+  NavigationGuard,
+  RouteLocationNormalized,
+  NavigationGuardNext,
+} from 'vue-router'
+
+const transitionViewGuard: NavigationGuard = (
+  to: RouteLocationNormalized,
+  from: RouteLocationNormalized,
+  next: NavigationGuardNext,
+) => {
+  // For now we need to add a workaround solution with a route level for the different transition types
+  // until the following feature was added: https://github.com/vuejs/vue-router/issues/3453.
+  const { setViewTransition } = useViewTransition()
+
+  let newViewTransition: ViewTransitions = ViewTransitions.REPLACE
+
+  // In the case that the 'To'-Route has no level, we use the replace transition.
+  if (to.meta?.level) {
+    const previousLevel = from.meta?.level || 1
+
+    if (previousLevel !== to.meta.level) {
+      newViewTransition =
+        previousLevel < to.meta.level
+          ? ViewTransitions.NEXT
+          : ViewTransitions.PREV
+    }
+  }
+
+  setViewTransition(newViewTransition)
+
+  next()
+}
+
+export default transitionViewGuard

+ 2 - 0
app/frontend/apps/mobile/router/routes/home.ts

@@ -12,6 +12,8 @@ const route: RouteRecordRaw = {
     title: __('Home'),
     requiresAuth: true,
     requiredPermission: ['*'],
+    hasBottomNavigation: true,
+    level: 1,
   },
 }
 

+ 2 - 0
app/frontend/apps/mobile/router/routes/ticketOverview.ts

@@ -12,6 +12,8 @@ const route: RouteRecordRaw = {
     title: __('Ticket Overviews'),
     requiresAuth: true,
     requiredPermission: ['ticket.agent', 'ticket.customer'],
+    hasBottomNavigation: true,
+    level: 2,
   },
 }
 

Некоторые файлы не были показаны из-за большого количества измененных файлов