| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- <template>
- <q-layout class="main-layout relative" view="hHh lpR fFf">
- <q-header
- v-if="$q.screen.lt.sm"
- class="bg-surface column justify-end"
- :style="{
- height: `calc(50px + env(safe-area-inset-top))`,
- }"
- >
- </q-header>
- <q-page-container>
- <q-page class="bg-surface main-layout-page" style="overflow: hidden;">
- <q-scroll-area
- ref="scrollAreaRef"
- class="main-layout-scroll-area"
- :style="scrollAreaHeight"
- :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 }">
- <Transition mode="out-in">
- <component
- :is="Component"
- class="main-layout-view"
- :class="{ 'main-layout-view--mobile': $q.screen.lt.sm }"
- />
- </Transition>
- </router-view>
- </q-scroll-area>
- </q-page>
- </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>
- </template>
- <script setup>
- import { computed, useTemplateRef, watch } from "vue";
- import { useQuasar } from "quasar";
- import { useRoute } from "vue-router";
- defineOptions({
- name: "MainLayout",
- });
- const $q = useQuasar();
- const route = useRoute();
- const scrollAreaRef = useTemplateRef("scrollAreaRef");
- let oldValue = route.path;
- 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 isNavItemActive = (item) => route.name === item.name;
- const scrollAreaHeight = computed(() => {
- if ($q.screen.lt.sm) {
- return 'height: calc(100dvh - 50px - env(safe-area-inset-top) - 80px - env(safe-area-inset-bottom)) !important;';
- }
- return 'height: 100dvh !important;';
- });
- watch(
- () => route.path,
- (value) => {
- if (oldValue !== value) {
- scrollAreaRef.value?.setScrollPosition("vertical", 0, 0);
- scrollAreaRef.value?.setScrollPosition("horizontal", 0, 0);
- }
- oldValue = value;
- }
- );
- </script>
- <style scoped>
- .main-layout {
- width: 100%;
- max-width: 100%;
- overflow-x: hidden;
- }
- .main-layout-page {
- width: 100%;
- max-width: 100%;
- overflow: 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 {
- opacity: 1;
- transition: all 0.15s ease-in;
- }
- .v-leave-active {
- opacity: 1;
- transition: all 0.15s ease-out;
- }
- .v-enter-from,
- .v-leave-to {
- opacity: 0;
- transition: all 0.15s ease-in;
- }
- .v-leave-to {
- 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>
|