|
@@ -1,135 +1,142 @@
|
|
|
<template>
|
|
<template>
|
|
|
- <q-layout class="relative" view="hHh lpR fFf">
|
|
|
|
|
- <LeftMenuLayout v-if="!$q.screen.lt.sm" />
|
|
|
|
|
- <LeftMenuLayoutMobile v-else v-model="leftDrawerOpen" />
|
|
|
|
|
|
|
+ <q-layout class="main-layout relative" view="hHh lpR fFf">
|
|
|
<q-header
|
|
<q-header
|
|
|
v-if="$q.screen.lt.sm"
|
|
v-if="$q.screen.lt.sm"
|
|
|
- class="bg-transparent column justify-end"
|
|
|
|
|
|
|
+ class="bg-surface column justify-end"
|
|
|
:style="{
|
|
:style="{
|
|
|
height: `calc(50px + env(safe-area-inset-top))`,
|
|
height: `calc(50px + env(safe-area-inset-top))`,
|
|
|
}"
|
|
}"
|
|
|
>
|
|
>
|
|
|
- <q-toolbar
|
|
|
|
|
- class="flex justify-between bg-primary"
|
|
|
|
|
- style="border-radius: 0 0 6px 6px !important"
|
|
|
|
|
- >
|
|
|
|
|
- <q-btn dense flat @click="toggleLeftDrawer">
|
|
|
|
|
- <q-icon name="menu" :color="$q.dark.isActive ? 'white' : 'black'" />
|
|
|
|
|
- </q-btn>
|
|
|
|
|
- <q-btn dense flat>
|
|
|
|
|
- <img
|
|
|
|
|
- :src="someAvatar()"
|
|
|
|
|
- alt="avatar"
|
|
|
|
|
- style="width: 20px; height: 20px; border-radius: 50%"
|
|
|
|
|
- />
|
|
|
|
|
- <q-menu anchor="center right" self="top start">
|
|
|
|
|
- <q-list class="column no-wrap overflow-hidden">
|
|
|
|
|
- <q-item
|
|
|
|
|
- v-ripple
|
|
|
|
|
- v-close-popup
|
|
|
|
|
- clickable
|
|
|
|
|
- :to="{ name: 'ProfilePage' }"
|
|
|
|
|
- exact
|
|
|
|
|
- exact-active-class="menu-selected"
|
|
|
|
|
- >
|
|
|
|
|
- <div class="flex">
|
|
|
|
|
- <q-item-section avatar>
|
|
|
|
|
- <q-icon
|
|
|
|
|
- name="account_circle"
|
|
|
|
|
- color="primary"
|
|
|
|
|
- style="font-size: 18px"
|
|
|
|
|
- />
|
|
|
|
|
- </q-item-section>
|
|
|
|
|
- <q-item-section>{{
|
|
|
|
|
- $t("user.profile.singular")
|
|
|
|
|
- }}</q-item-section>
|
|
|
|
|
- </div>
|
|
|
|
|
- </q-item>
|
|
|
|
|
- <q-item v-ripple clickable @click="logoutFn">
|
|
|
|
|
- <div class="flex">
|
|
|
|
|
- <q-item-section avatar>
|
|
|
|
|
- <q-icon
|
|
|
|
|
- name="logout"
|
|
|
|
|
- color="negative"
|
|
|
|
|
- style="font-size: 18px"
|
|
|
|
|
- />
|
|
|
|
|
- </q-item-section>
|
|
|
|
|
- <q-item-section>{{ $t("auth.logout") }}</q-item-section>
|
|
|
|
|
- </div>
|
|
|
|
|
- </q-item>
|
|
|
|
|
- </q-list>
|
|
|
|
|
- </q-menu>
|
|
|
|
|
- </q-btn>
|
|
|
|
|
- </q-toolbar>
|
|
|
|
|
</q-header>
|
|
</q-header>
|
|
|
<q-page-container>
|
|
<q-page-container>
|
|
|
- <q-page>
|
|
|
|
|
|
|
+ <q-page class="bg-surface main-layout-page">
|
|
|
<q-scroll-area
|
|
<q-scroll-area
|
|
|
ref="scrollAreaRef"
|
|
ref="scrollAreaRef"
|
|
|
- :style="
|
|
|
|
|
- $q.screen.lt.sm
|
|
|
|
|
- ? 'height: calc(100dvh - 68px - env(safe-area-inset-top)) !important;'
|
|
|
|
|
- : 'height: calc(100dvh - env(safe-area-inset-top)) !important;'
|
|
|
|
|
- "
|
|
|
|
|
|
|
+ class="main-layout-scroll-area"
|
|
|
|
|
+ :style="scrollAreaStyle"
|
|
|
|
|
+ :content-style="{ width: '100%', maxWidth: '100%', overflowX: 'hidden', boxSizing: 'border-box' }"
|
|
|
|
|
+ :content-active-style="{ width: '100%', maxWidth: '100%', overflowX: 'hidden', boxSizing: 'border-box' }"
|
|
|
>
|
|
>
|
|
|
<router-view v-slot="{ Component }">
|
|
<router-view v-slot="{ Component }">
|
|
|
<Transition mode="out-in">
|
|
<Transition mode="out-in">
|
|
|
<component
|
|
<component
|
|
|
:is="Component"
|
|
:is="Component"
|
|
|
- style="padding: 20px !important; padding-right: 10px !important"
|
|
|
|
|
- :style="$q.screen.lt.sm ? 'padding-left: 10px !important;' : ''"
|
|
|
|
|
|
|
+ class="main-layout-view"
|
|
|
|
|
+ :class="{ 'main-layout-view--mobile': $q.screen.lt.sm }"
|
|
|
/>
|
|
/>
|
|
|
</Transition>
|
|
</Transition>
|
|
|
</router-view>
|
|
</router-view>
|
|
|
</q-scroll-area>
|
|
</q-scroll-area>
|
|
|
</q-page>
|
|
</q-page>
|
|
|
</q-page-container>
|
|
</q-page-container>
|
|
|
|
|
+ <q-footer v-if="$q.screen.lt.sm" class="provider-bottom-nav bg-white">
|
|
|
|
|
+ <nav class="provider-bottom-nav-inner">
|
|
|
|
|
+ <router-link
|
|
|
|
|
+ v-for="item in navItems"
|
|
|
|
|
+ :key="item.name"
|
|
|
|
|
+ :to="{ name: item.name }"
|
|
|
|
|
+ class="provider-bottom-nav-item"
|
|
|
|
|
+ :class="{ 'provider-bottom-nav-item--active': isNavItemActive(item) }"
|
|
|
|
|
+ >
|
|
|
|
|
+ <q-icon :name="item.icon" class="provider-bottom-nav-icon" />
|
|
|
|
|
+ <span class="provider-bottom-nav-label">{{ item.label }}</span>
|
|
|
|
|
+ </router-link>
|
|
|
|
|
+ </nav>
|
|
|
|
|
+ </q-footer>
|
|
|
</q-layout>
|
|
</q-layout>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { ref, useTemplateRef, watch } from "vue";
|
|
|
|
|
|
|
+import { computed, useTemplateRef, watch } from "vue";
|
|
|
|
|
+import { useQuasar } from "quasar";
|
|
|
import { useRoute } from "vue-router";
|
|
import { useRoute } from "vue-router";
|
|
|
-import { useAuth } from "src/composables/useAuth";
|
|
|
|
|
-import { useRouter } from "vue-router";
|
|
|
|
|
-import LeftMenuLayout from "src/components/layout/LeftMenuLayout.vue";
|
|
|
|
|
-import LeftMenuLayoutMobile from "src/components/layout/LeftMenuLayoutMobile.vue";
|
|
|
|
|
|
|
|
|
|
defineOptions({
|
|
defineOptions({
|
|
|
name: "MainLayout",
|
|
name: "MainLayout",
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-const { logout } = useAuth();
|
|
|
|
|
|
|
+const $q = useQuasar();
|
|
|
const route = useRoute();
|
|
const route = useRoute();
|
|
|
-const leftDrawerOpen = ref(false);
|
|
|
|
|
const scrollAreaRef = useTemplateRef("scrollAreaRef");
|
|
const scrollAreaRef = useTemplateRef("scrollAreaRef");
|
|
|
-const router = useRouter();
|
|
|
|
|
|
|
|
|
|
let oldValue = route.path;
|
|
let oldValue = route.path;
|
|
|
|
|
|
|
|
-const someAvatar = () => {
|
|
|
|
|
- let random = Math.floor(Math.random() * 5) + 1;
|
|
|
|
|
- return "https://cdn.quasar.dev/img/avatar" + random + ".jpg";
|
|
|
|
|
-};
|
|
|
|
|
|
|
+const navItems = [
|
|
|
|
|
+ {
|
|
|
|
|
+ name: "DashboardPage",
|
|
|
|
|
+ label: "Início",
|
|
|
|
|
+ icon: "mdi-home-outline",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: "SearchPage",
|
|
|
|
|
+ label: "Busca",
|
|
|
|
|
+ icon: "mdi-magnify",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: "AgendaPage",
|
|
|
|
|
+ label: "Agenda",
|
|
|
|
|
+ icon: "mdi-calendar-blank-outline",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: "ProfilePage",
|
|
|
|
|
+ label: "Perfil",
|
|
|
|
|
+ icon: "mdi-account-circle-outline",
|
|
|
|
|
+ },
|
|
|
|
|
+];
|
|
|
|
|
+
|
|
|
|
|
+const scrollAreaStyle = computed(() => {
|
|
|
|
|
+ if ($q.screen.lt.sm) {
|
|
|
|
|
+ return `height: calc(100dvh - env(safe-area-inset-top) - env(safe-area-inset-bottom)) !important;`;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-const logoutFn = async () => {
|
|
|
|
|
- await logout();
|
|
|
|
|
- router.push({ name: "LoginPage" });
|
|
|
|
|
-};
|
|
|
|
|
|
|
+ return "height: calc(100dvh - env(safe-area-inset-top)) !important;";
|
|
|
|
|
+});
|
|
|
|
|
|
|
|
-const toggleLeftDrawer = () => {
|
|
|
|
|
- leftDrawerOpen.value = !leftDrawerOpen.value;
|
|
|
|
|
-};
|
|
|
|
|
|
|
+const isNavItemActive = (item) => route.name === item.name;
|
|
|
|
|
|
|
|
-watch(route, (value) => {
|
|
|
|
|
- if (oldValue.path != value.path) {
|
|
|
|
|
- scrollAreaRef.value.setScrollPosition("vertical", 0, 0);
|
|
|
|
|
- scrollAreaRef.value.setScrollPosition("horizontal", 0, 0);
|
|
|
|
|
|
|
+watch(
|
|
|
|
|
+ () => route.path,
|
|
|
|
|
+ (value) => {
|
|
|
|
|
+ if (oldValue !== value) {
|
|
|
|
|
+ scrollAreaRef.value?.setScrollPosition("vertical", 0, 0);
|
|
|
|
|
+ scrollAreaRef.value?.setScrollPosition("horizontal", 0, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ oldValue = value;
|
|
|
}
|
|
}
|
|
|
- oldValue = value.path;
|
|
|
|
|
-});
|
|
|
|
|
|
|
+);
|
|
|
</script>
|
|
</script>
|
|
|
<style scoped>
|
|
<style scoped>
|
|
|
|
|
+.main-layout {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ max-width: 100%;
|
|
|
|
|
+ overflow-x: hidden;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.main-layout-page {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ max-width: 100%;
|
|
|
|
|
+ overflow-x: hidden;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.main-layout-scroll-area {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ max-width: 100%;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.main-layout-view {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ max-width: 100%;
|
|
|
|
|
+ min-width: 0;
|
|
|
|
|
+ padding: 0 !important;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ overflow-x: hidden;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.main-layout-view--mobile {
|
|
|
|
|
+ padding: 0 !important;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
.v-enter-active {
|
|
.v-enter-active {
|
|
|
opacity: 1;
|
|
opacity: 1;
|
|
|
transition: all 0.15s ease-in;
|
|
transition: all 0.15s ease-in;
|
|
@@ -149,4 +156,49 @@ watch(route, (value) => {
|
|
|
.v-leave-to {
|
|
.v-leave-to {
|
|
|
transition: all 0.15s ease-out;
|
|
transition: all 0.15s ease-out;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+.provider-bottom-nav {
|
|
|
|
|
+ background: #ffffff;
|
|
|
|
|
+ box-shadow: 0 -12px 30px rgba(38, 27, 52, 0.1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.provider-bottom-nav-inner {
|
|
|
|
|
+ display: grid;
|
|
|
|
|
+ grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
|
|
|
+ align-items: end;
|
|
|
|
|
+ height: 80px;
|
|
|
|
|
+ padding: 12px 10px calc(12px + env(safe-area-inset-bottom));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.provider-bottom-nav-item {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: flex-end;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ min-height: 56px;
|
|
|
|
|
+ color: #a1a1a1;
|
|
|
|
|
+ text-decoration: none;
|
|
|
|
|
+ transition: color 0.2s ease;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.provider-bottom-nav-item--active {
|
|
|
|
|
+ color: #ff00ea;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.provider-bottom-nav-icon {
|
|
|
|
|
+ font-size: 30px;
|
|
|
|
|
+ line-height: 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.provider-bottom-nav-label {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ font-weight: 400;
|
|
|
|
|
+ line-height: 1.1;
|
|
|
|
|
+ letter-spacing: -0.02em;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.provider-bottom-nav-item--active .provider-bottom-nav-label {
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|