Bladeren bron

inicio layout prestador app

Gustavo Zanatta 1 maand geleden
bovenliggende
commit
0dcd604ccb

+ 12 - 0
src/assets/logo_diaria_colorido_sem_texto.svg

@@ -0,0 +1,12 @@
+<svg width="24" height="23" viewBox="0 0 24 23" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12.8391 0.000430053H2.10087C0.232825 0.000430053 -0.702493 2.25278 0.618337 3.57013L2.13408 5.08188C2.58082 5.52744 3.18669 5.77775 3.81886 5.77775H12.8391C15.8038 5.77775 18.207 8.17461 18.207 11.1314V11.851C18.207 13.4849 17.4579 14.9523 16.2863 15.9234C15.9564 16.197 15.8577 16.6593 16.0591 17.0369L16.9763 18.7564C17.157 19.0854 16.7714 19.4342 16.4605 19.2231L14.0418 17.338C13.8745 17.2077 13.6658 17.1389 13.4536 17.1505C13.2557 17.1612 13.0785 17.1436 12.8279 17.1436H3.81886C3.18712 17.1436 2.58082 17.3939 2.13408 17.8395L0.7007 19.2691C-0.650747 20.617 0.306564 22.9213 2.21774 22.9213H12.8353C19.0013 22.9213 24 17.9358 24 11.786V11.1314C24 4.98382 19.003 0 12.8391 0V0.000430053Z" fill="url(#paint0_linear_3102_1251)"/>
+<path d="M5.70554 9.41709L6.05263 10.1518C6.08152 10.2124 6.13685 10.2548 6.20114 10.2646L6.9771 10.3828C7.13864 10.4074 7.20334 10.6143 7.08656 10.7334L6.52422 11.3066C6.47784 11.3537 6.45668 11.4215 6.46766 11.488L6.60031 12.2978C6.62798 12.4657 6.4583 12.5937 6.31345 12.5144L5.6205 12.1333C5.56272 12.1015 5.49395 12.1015 5.43617 12.1333L4.74282 12.5144C4.59796 12.5941 4.42869 12.4661 4.45596 12.2978L4.5886 11.488C4.59959 11.4215 4.57843 11.3537 4.53205 11.3066L3.96971 10.7334C3.85293 10.6143 3.91763 10.4074 4.07917 10.3828L4.85594 10.2646C4.92023 10.2548 4.97597 10.2124 5.00445 10.1518L5.35113 9.41752C5.42356 9.26447 5.63311 9.26447 5.70513 9.41752L5.70554 9.41709Z" fill="#FE7FFF"/>
+<path d="M10.1696 9.41709L10.5456 10.1518C10.5769 10.2124 10.6369 10.2548 10.7065 10.2646L11.5471 10.3828C11.7221 10.4074 11.7922 10.6143 11.6657 10.7334L11.0565 11.3066C11.0063 11.3537 10.9833 11.4215 10.9952 11.488L11.1389 12.2978C11.1689 12.4657 10.9851 12.5937 10.8282 12.5144L10.0775 12.1333C10.0149 12.1015 9.94039 12.1015 9.8778 12.1333L9.12666 12.5144C8.96973 12.5941 8.78636 12.4661 8.81589 12.2978L8.95959 11.488C8.9715 11.4215 8.94857 11.3537 8.89832 11.3066L8.28913 10.7334C8.16262 10.6143 8.2327 10.4074 8.4077 10.3828L9.2492 10.2646C9.31885 10.2548 9.37924 10.2124 9.4101 10.1518L9.78567 9.41752C9.86413 9.26447 10.0911 9.26447 10.1692 9.41752L10.1696 9.41709Z" fill="#FE7FFF"/>
+<path d="M14.7536 9.41709L15.1296 10.1518C15.1609 10.2124 15.2209 10.2548 15.2905 10.2646L16.1311 10.3828C16.3061 10.4074 16.3762 10.6143 16.2497 10.7334L15.6405 11.3066C15.5902 11.3537 15.5673 11.4215 15.5792 11.488L15.7229 12.2978C15.7529 12.4657 15.5691 12.5937 15.4122 12.5144L14.6615 12.1333C14.5989 12.1015 14.5244 12.1015 14.4618 12.1333L13.7106 12.5144C13.5537 12.5941 13.3703 12.4661 13.3999 12.2978L13.5436 11.488C13.5555 11.4215 13.5326 11.3537 13.4823 11.3066L12.8731 10.7334C12.7466 10.6143 12.8167 10.4074 12.9917 10.3828L13.8332 10.2646C13.9028 10.2548 13.9632 10.2124 13.9941 10.1518L14.3697 9.41752C14.4481 9.26447 14.6751 9.26447 14.7532 9.41752L14.7536 9.41709Z" fill="#FE7FFF"/>
+<defs>
+<linearGradient id="paint0_linear_3102_1251" x1="12" y1="0.000430084" x2="12" y2="22.9218" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FE7FFF"/>
+<stop offset="1" stop-color="#2F80ED"/>
+</linearGradient>
+</defs>
+</svg>

+ 24 - 0
src/css/app.scss

@@ -113,4 +113,28 @@ input[type="number"]::-webkit-outer-spin-button {
   font-size: 15px;
   color: #ffffff;
   text-transform: lowercase;
+}
+
+.gradient-diarista {
+  background: linear-gradient(
+    -90deg,
+    #ec48d1 5%,
+    #6b11cb 65%,
+    #2574fc 100%
+  );
+
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+
+  background-clip: text;
+  color: transparent;
+}
+
+.gradient-diarista-bg {
+  background: linear-gradient(
+    -90deg,
+    #ec48d1 1%,
+    #6b11cbcb 65%,
+    #2574fcbd 100%
+  );
 }

+ 150 - 44
src/layouts/MainLayout.vue

@@ -1,22 +1,22 @@
 <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">
+    <!-- <LeftMenuLayout v-if="!$q.screen.lt.sm" />
+    <LeftMenuLayoutMobile v-else v-model="leftDrawerOpen" /> -->
     <q-header
       v-if="$q.screen.lt.sm"
-      class="bg-transparent column justify-end"
+      class="bg-surface column justify-end"
       :style="{
         height: `calc(50px + env(safe-area-inset-top))`,
       }"
     >
-      <q-toolbar
+      <!-- <q-toolbar
         class="flex justify-between bg-primary"
         style="border-radius: 0 0 6px 6px !important"
-      >
-        <q-btn dense flat @click="toggleLeftDrawer">
+      > -->
+        <!-- <q-btn dense flat @click="toggleLeftDrawer">
           <q-icon name="menu" :color="$q.dark.isActive ? 'white' : 'black'" />
-        </q-btn>
-        <q-btn dense flat>
+        </q-btn> -->
+        <!-- <q-btn dense flat>
           <img
             :src="someAvatar()"
             alt="avatar"
@@ -59,77 +59,138 @@
               </q-item>
             </q-list>
           </q-menu>
-        </q-btn>
-      </q-toolbar>
+        </q-btn> -->
+      <!-- </q-toolbar> -->
     </q-header>
     <q-page-container>
-      <q-page>
+      <q-page class="bg-surface">
         <q-scroll-area
           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;'
-          "
+          :style="scrollAreaStyle"
         >
           <router-view v-slot="{ Component }">
             <Transition mode="out-in">
               <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>
           </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 { ref, useTemplateRef, watch } from "vue";
+import { computed, useTemplateRef, watch } from "vue";
+import { useQuasar } from "quasar";
 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";
+// 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({
   name: "MainLayout",
 });
 
-const { logout } = useAuth();
+// const { logout } = useAuth();
+const $q = useQuasar();
 const route = useRoute();
-const leftDrawerOpen = ref(false);
+// const leftDrawerOpen = ref(false);
 const scrollAreaRef = useTemplateRef("scrollAreaRef");
-const router = useRouter();
+// const router = useRouter();
+
+const MOBILE_HEADER_HEIGHT = 68;
+const MOBILE_BOTTOM_NAV_HEIGHT = 102;
 
 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 - ${MOBILE_HEADER_HEIGHT}px - env(safe-area-inset-top) - ${MOBILE_BOTTOM_NAV_HEIGHT}px - env(safe-area-inset-bottom)) !important;`;
+  }
+
+  return "height: calc(100dvh - env(safe-area-inset-top)) !important;";
+});
+
+const isNavItemActive = (item) => route.name === item.name;
 
-const logoutFn = async () => {
-  await logout();
-  router.push({ name: "LoginPage" });
-};
+// const someAvatar = () => {
+//   let random = Math.floor(Math.random() * 5) + 1;
+//   return "https://cdn.quasar.dev/img/avatar" + random + ".jpg";
+// };
 
-const toggleLeftDrawer = () => {
-  leftDrawerOpen.value = !leftDrawerOpen.value;
-};
+// const logoutFn = async () => {
+//   await logout();
+//   router.push({ name: "LoginPage" });
+// };
 
-watch(route, (value) => {
-  if (oldValue.path != value.path) {
-    scrollAreaRef.value.setScrollPosition("vertical", 0, 0);
-    scrollAreaRef.value.setScrollPosition("horizontal", 0, 0);
+// const toggleLeftDrawer = () => {
+//   leftDrawerOpen.value = !leftDrawerOpen.value;
+// };
+
+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>
 <style scoped>
+.main-layout__view {
+  padding: 20px !important;
+  padding-right: 10px !important;
+}
+
+.main-layout__view--mobile {
+  padding-left: 10px !important;
+  padding-bottom: 18px !important;
+}
+
 .v-enter-active {
   opacity: 1;
   transition: all 0.15s ease-in;
@@ -149,4 +210,49 @@ watch(route, (value) => {
 .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;
+  min-height: 56px;
+  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>

+ 52 - 0
src/pages/agenda/AgendaPage.vue

@@ -0,0 +1,52 @@
+<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
+<template>
+  <section class="mobile-placeholder">
+    <div class="mobile-placeholder__badge">
+      <q-icon name="mdi-calendar-blank-outline" />
+    </div>
+    <h1 class="mobile-placeholder__title">Agenda</h1>
+    <p class="mobile-placeholder__description">
+      Área reservada para exibir compromissos, confirmações e próximas diárias.
+    </p>
+  </section>
+</template>
+
+<style scoped>
+.mobile-placeholder {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  min-height: calc(100dvh - 240px);
+  padding: 32px 20px;
+  text-align: center;
+}
+
+.mobile-placeholder__badge {
+  display: grid;
+  place-items: center;
+  width: 88px;
+  height: 88px;
+  border-radius: 28px;
+  margin-bottom: 20px;
+  background: linear-gradient(180deg, rgba(255, 0, 234, 0.14), rgba(107, 17, 203, 0.08));
+  color: #ff00ea;
+  font-size: 44px;
+}
+
+.mobile-placeholder__title {
+  margin: 0 0 8px;
+  font-size: 28px;
+  font-weight: 700;
+  line-height: 1.1;
+  color: #4d4d4d;
+}
+
+.mobile-placeholder__description {
+  max-width: 280px;
+  margin: 0;
+  font-size: 16px;
+  line-height: 1.5;
+  color: #8d8d8d;
+}
+</style>

+ 52 - 0
src/pages/profile/ProfilePage.vue

@@ -0,0 +1,52 @@
+<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
+<template>
+  <section class="mobile-placeholder">
+    <div class="mobile-placeholder__badge">
+      <q-icon name="mdi-account-circle-outline" />
+    </div>
+    <h1 class="mobile-placeholder__title">Perfil</h1>
+    <p class="mobile-placeholder__description">
+      Área reservada para informações da conta, dados profissionais e preferências.
+    </p>
+  </section>
+</template>
+
+<style scoped>
+.mobile-placeholder {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  min-height: calc(100dvh - 240px);
+  padding: 32px 20px;
+  text-align: center;
+}
+
+.mobile-placeholder__badge {
+  display: grid;
+  place-items: center;
+  width: 88px;
+  height: 88px;
+  border-radius: 28px;
+  margin-bottom: 20px;
+  background: linear-gradient(180deg, rgba(255, 0, 234, 0.14), rgba(107, 17, 203, 0.08));
+  color: #ff00ea;
+  font-size: 44px;
+}
+
+.mobile-placeholder__title {
+  margin: 0 0 8px;
+  font-size: 28px;
+  font-weight: 700;
+  line-height: 1.1;
+  color: #4d4d4d;
+}
+
+.mobile-placeholder__description {
+  max-width: 280px;
+  margin: 0;
+  font-size: 16px;
+  line-height: 1.5;
+  color: #8d8d8d;
+}
+</style>

+ 52 - 0
src/pages/search/SearchPage.vue

@@ -0,0 +1,52 @@
+<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
+<template>
+  <section class="mobile-placeholder">
+    <div class="mobile-placeholder__badge">
+      <q-icon name="mdi-magnify" />
+    </div>
+    <h1 class="mobile-placeholder__title">Busca</h1>
+    <p class="mobile-placeholder__description">
+      Área reservada para a busca de diárias e oportunidades próximas.
+    </p>
+  </section>
+</template>
+
+<style scoped>
+.mobile-placeholder {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  min-height: calc(100dvh - 240px);
+  padding: 32px 20px;
+  text-align: center;
+}
+
+.mobile-placeholder__badge {
+  display: grid;
+  place-items: center;
+  width: 88px;
+  height: 88px;
+  border-radius: 28px;
+  margin-bottom: 20px;
+  background: linear-gradient(180deg, rgba(255, 0, 234, 0.14), rgba(107, 17, 203, 0.08));
+  color: #ff00ea;
+  font-size: 44px;
+}
+
+.mobile-placeholder__title {
+  margin: 0 0 8px;
+  font-size: 28px;
+  font-weight: 700;
+  line-height: 1.1;
+  color: #4d4d4d;
+}
+
+.mobile-placeholder__description {
+  max-width: 280px;
+  margin: 0;
+  font-size: 16px;
+  line-height: 1.5;
+  color: #8d8d8d;
+}
+</style>

+ 57 - 0
src/router/routes.js

@@ -28,6 +28,63 @@ const routes = [
           ],
         },
       },
+      {
+        path: "busca",
+        name: "SearchPage",
+        component: () => import("src/pages/search/SearchPage.vue"),
+        meta: {
+          title: "Busca",
+          requireAuth: true,
+          breadcrumbs: [
+            {
+              name: "DashboardPage",
+              title: "ui.navigation.dashboard",
+            },
+            {
+              name: "SearchPage",
+              title: "Busca",
+            },
+          ],
+        },
+      },
+      {
+        path: "agenda",
+        name: "AgendaPage",
+        component: () => import("src/pages/agenda/AgendaPage.vue"),
+        meta: {
+          title: "Agenda",
+          requireAuth: true,
+          breadcrumbs: [
+            {
+              name: "DashboardPage",
+              title: "ui.navigation.dashboard",
+            },
+            {
+              name: "AgendaPage",
+              title: "Agenda",
+            },
+          ],
+        },
+      },
+      {
+        path: "perfil",
+        name: "ProfilePage",
+        component: () => import("src/pages/profile/ProfilePage.vue"),
+        meta: {
+          title: "Perfil",
+          requireAuth: true,
+          breadcrumbs: [
+            {
+              name: "DashboardPage",
+              title: "ui.navigation.dashboard",
+            },
+            {
+              name: "ProfilePage",
+              title: "Perfil",
+            },
+          ],
+        },
+      },
       ...sub_routes,
     ],
   },