Selaa lähdekoodia

feat: :sparkles: Mudando MainLayout e LeftMenu

Denis 1 vuosi sitten
vanhempi
commit
ca5cbe3fe7

+ 1 - 1
quasar.config.js

@@ -40,7 +40,7 @@ export default configure((ctx) => {
         node: "node20",
       },
 
-      vueRouterMode: "hash", // available values: 'hash', 'history'
+      vueRouterMode: "history", // available values: 'hash', 'history'
       // vueRouterBase,
       // vueDevtools,
       // vueOptionsAPI: false,

+ 196 - 60
src/components/geral/LeftMenuLayout.vue

@@ -1,91 +1,220 @@
 <template>
   <q-drawer
+    v-bind="$attrs"
     v-model="leftDrawerOpen"
     show-if-above
-    :mini="miniState"
-    mini-to-overlay
     :width="250"
+    :mini-width="70"
     :breakpoint="500"
-    bordered
-    @mouseover="miniState = false"
-    @mouseout="miniState = true"
+    :mini="miniState"
+    class="detached-container"
   >
-    <q-scroll-area style="height: calc(100vh - 100px)">
-      <q-list class="column no-wrap" style="height: calc(100vh - 100px)">
+    <div class="q-pa-sm">
+      <div
+        class="toggle-button-wrapper absolute"
+        style="top: 50%; right: -32px; z-index: 1"
+      >
+        <q-btn flat round size="sm" @click="miniState = !miniState">
+          <q-icon
+            :name="miniState ? 'mdi-chevron-right' : 'mdi-chevron-left'"
+          />
+          <q-tooltip
+            anchor="center right"
+            self="center left"
+            :offset="[10, 10]"
+            >{{ miniState ? "Expandir menu" : "Colapsar menu" }}</q-tooltip
+          >
+        </q-btn>
+      </div>
+
+      <q-list class="column q-mb-md no-wrap" style="border-radius: 6px">
+        <q-item v-ripple clickable>
+          <div class="flex">
+            <q-item-section avatar>
+              <template #default>
+                <img
+                  :src="someAvatar()"
+                  alt="avatar"
+                  style="width: 20px; height: 20px; border-radius: 50%"
+                />
+              </template>
+            </q-item-section>
+            <q-item-section>Usuario</q-item-section>
+          </div>
+          <q-tooltip
+            v-if="miniState"
+            anchor="center right"
+            self="center left"
+            :offset="[10, 10]"
+            >Usuario</q-tooltip
+          >
+        </q-item>
+      </q-list>
+
+      <q-list class="column no-wrap">
         <template v-for="menu in menus" :key="menu.name">
-          <!-- * Single menu -->
+          <!-- Single Menu -->
           <q-item
-            v-if="menu.type == 'single' && menu.permission"
+            v-if="menu.type === 'single'"
             v-ripple
             clickable
-            :to="{ name: menu.name }"
-            :disable="menu.disable"
-            class="text-subtitle1"
             exact-active-class="menu-selected"
             exact
             active-class="menu-selected"
+            :to="{ name: menu.name }"
+            class="q-my-xs"
           >
             <q-item-section avatar>
-              <q-icon :name="menu.icon" />
+              <q-icon :name="menu.icon" style="font-size: 18px" />
             </q-item-section>
-
-            <q-item-section> {{ $t(menu.title) }} </q-item-section>
+            <q-item-section>{{ $t(menu.title) }}</q-item-section>
+            <q-tooltip
+              v-if="miniState"
+              anchor="center right"
+              self="center left"
+              :offset="[10, 10]"
+              >{{ $t(menu.title) }}</q-tooltip
+            >
           </q-item>
-          <q-expansion-item
-            v-if="menu.type == 'expansive' && menu.permission"
-            expand-separator
-            header-class="text-subtitle1"
-            :icon="menu.icon"
-            :label="$t(menu.title)"
-            :content-inset-level="0.4"
-            :disable="menu.disable"
-          >
-            <template v-for="children in menu.childrens" :key="children.name">
+          <!-- Expansive Menu with children -->
+          <div v-else>
+            <template v-if="!miniState">
+              <q-tooltip
+                v-if="miniState"
+                anchor="center right"
+                self="center left"
+                :offset="[10, 10]"
+                >{{ $t(menu.title) }}</q-tooltip
+              >
+              <q-expansion-item
+                v-model="isExpasionItemExpanded"
+                header-class=" menu-item--spaced"
+                :class="{
+                  'menu-selected':
+                    childrenAreActive(menu.children) && !isExpasionItemExpanded,
+                }"
+                class="menu-item--spaced"
+              >
+                <template #header>
+                  <q-item-section avatar>
+                    <q-icon :name="menu.icon" style="font-size: 18px" />
+                  </q-item-section>
+                  <q-item-section>{{ $t(menu.title) }}</q-item-section>
+                </template>
+                <div v-for="child in menu.childrens" :key="child.name">
+                  <q-item
+                    v-ripple
+                    clickable
+                    :to="{ name: child.name }"
+                    exact
+                    exact-active-class="menu-selected"
+                    class="menu-item--spaced"
+                  >
+                    <q-item-section avatar>
+                      <q-icon :name="child.icon" style="font-size: 18px" />
+                    </q-item-section>
+                    <q-item-section>{{ $t(child.title) }}</q-item-section>
+                    <q-tooltip
+                      v-if="miniState"
+                      anchor="center right"
+                      self="center left"
+                      :offset="[10, 10]"
+                      >{{ $t(child.title) }}</q-tooltip
+                    >
+                  </q-item>
+                </div>
+              </q-expansion-item>
+            </template>
+            <template v-else>
               <q-item
-                v-if="children.permission"
                 v-ripple
                 clickable
-                :to="{ name: children.name }"
-                :disable="children.disable"
-                class="text-subtitle1"
+                exact
                 exact-active-class="menu-selected"
+                class="menu-item--spaced"
+                @click="openMenu(menu)"
               >
                 <q-item-section avatar>
-                  <q-icon :name="children.icon" />
+                  <q-icon :name="menu.icon" style="font-size: 18px" />
                 </q-item-section>
-                <q-item-section> {{ $t(children.title) }} </q-item-section>
+                <q-item-section>{{ $t(menu.title) }}</q-item-section>
+                <q-tooltip
+                  v-if="miniState"
+                  anchor="center right"
+                  self="center left"
+                  :offset="[10, 10]"
+                  >{{ $t(menu.title) }}</q-tooltip
+                >
+                <q-menu anchor="top right" self="top left">
+                  <q-list style="min-width: 100px">
+                    <q-item
+                      v-for="child in menu.childrens"
+                      :key="child.name"
+                      v-ripple
+                      v-close-popup
+                      clickable
+                      :to="{ name: child.name }"
+                      exact
+                      exact-active-class="menu-selected"
+                      class="menu-item--spaced"
+                    >
+                      <q-item-section avatar>
+                        <q-icon :name="child.icon" style="font-size: 18px" />
+                      </q-item-section>
+                      <q-item-section>{{ $t(child.title) }}</q-item-section>
+                    </q-item>
+                  </q-list>
+                </q-menu>
               </q-item>
             </template>
-          </q-expansion-item>
+          </div>
         </template>
-        <q-item
-          v-ripple
-          clickable
-          class="q-mt-auto text-subtitle1"
-          @click="logout()"
-        >
+      </q-list>
+
+      <q-list class="column q-mt-md no-wrap overflow-hidden">
+        <q-item v-ripple clickable @click="logoutFn">
           <div class="flex">
             <q-item-section avatar>
-              <q-icon name="mdi-logout-variant" color="negative" />
+              <q-icon name="logout" color="negative" style="font-size: 18px" />
             </q-item-section>
-            <q-item-section> {{ $t("navigation.logout") }} </q-item-section>
+            <q-item-section>Sair</q-item-section>
           </div>
+          <q-tooltip
+            v-if="miniState"
+            anchor="center right"
+            self="center left"
+            :offset="[10, 10]"
+            >Sair</q-tooltip
+          >
         </q-item>
       </q-list>
-    </q-scroll-area>
+    </div>
   </q-drawer>
 </template>
-
 <script setup>
 import { ref, onMounted } from "vue";
 import { useAuth } from "src/composables/useAuth";
 import { permissionStore } from "src/stores/permission";
-import { useRouter } from "vue-router";
+import { useRouter, useRoute } from "vue-router";
 
-const auth = useAuth();
+const { logout } = useAuth();
 const leftDrawerOpen = ref(true);
 const miniState = ref(true);
 const router = useRouter();
+const route = useRoute();
+
+const childrenAreActive = (children) => {
+  if (!children) return false;
+  return children.some((child) => {
+    return route.path.includes(child.path);
+  });
+};
+
+const someAvatar = () => {
+  return "https://cdn.quasar.dev/img/avatar4.jpg";
+};
+
+const isExpasionItemExpanded = ref(false);
 
 const menus = ref([
   {
@@ -139,8 +268,8 @@ const getMenuAccess = () => {
     .filter((menu) => menu !== null);
 };
 
-const logout = async () => {
-  await auth.logout();
+const logoutFn = async () => {
+  await logout();
   router.push({ name: "LoginPage" });
 };
 
@@ -150,20 +279,27 @@ onMounted(() => {
 </script>
 
 <style lang="scss" scoped>
+@import "/src/css/quasar.variables.scss";
+.text-subtitle3 {
+  font-size: 1.1rem !important;
+  font-weight: 400 !important;
+}
+
 .menu-selected {
-  color: #385873 !important;
-  background: rgba(56, 88, 115, 0.15) !important;
-
-  .body--light & {
-    color: #385873 !important;
-  }
-
-  .body--dark & {
-    color: #5d93bf !important;
-  }
-  //sobreescrever comportamento padrao da classe .fit do quasar
-  .fit {
-    padding: 0px !important;
-  }
+  background-color: rgba($primary, 0.1);
+  color: $primary;
+}
+
+.toggle-button-wrapper {
+  transition: transform 0.3s ease;
+}
+
+.toggle-button-wrapper:hover {
+  transform: scale(1.1);
+}
+
+.menu-item--spaced {
+  margin-top: 5px;
+  margin-bottom: 5px;
 }
 </style>

+ 7 - 0
src/css/app.scss

@@ -6,3 +6,10 @@
     transition: border-color 0.36s cubic-bezier(0.4, 0, 0.2, 1);
   }
 }
+
+.q-drawer:has(.detached-container) {
+  margin: 16px !important;
+  margin-bottom: 16px !important;
+  margin-left: 10px !important;
+  border-radius: 6px !important;
+}

+ 9 - 105
src/layouts/MainLayout.vue

@@ -1,122 +1,26 @@
 <template>
-  <q-layout view="hHh LpR fff">
-    <q-header>
-      <q-toolbar>
-        <q-btn
-          flat
-          dense
-          round
-          icon="menu"
-          aria-label="Menu"
-          @click="toggleLeftDrawer"
-        />
-      </q-toolbar>
-    </q-header>
-
-    <LeftMenuLayout v-model="leftDrawerOpen" />
+  <q-layout class="relative" view="hHh lpR fFf">
+    <LeftMenuLayout
+      v-model="leftDrawerOpen"
+    />
 
     <q-page-container>
-      <router-view />
+      <q-page>
+        <q-scroll-area style="height: 100vh !important">
+          <router-view />
+        </q-scroll-area>
+      </q-page>
     </q-page-container>
-
-    <q-footer class="bg-header text-black">
-      <q-toolbar>
-        <q-toolbar-title>
-          <div class="flex justify-between">
-            <div class="flex cursor-pointer" @click="() => {}">
-              <span class="text-subtitle1 text-black q-my-auto flex q-pl-sm">{{
-                version
-              }}</span>
-            </div>
-            <div class="flex">
-              <img :src="darkLogo" alt="logo" class="q-my-auto q-ml-xl" />
-              <div class="flex q-ml-sm">
-                <!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
-                <span class="q-my-auto"> ® </span>
-                <span class="text-caption q-my-auto q-pb-xs q-pl-xs">
-                  {{ year }}
-                </span>
-              </div>
-            </div>
-            <div class="flex justify-end q-my-auto">
-              <div class="flex flex-center q-mr-md">
-                <q-icon
-                  size="sm"
-                  name="mdi-translate"
-                  class="cursor-pointer"
-                  :class="{
-                    'text-black': !$q.dark.isActive,
-                    'text-white': $q.dark.isActive,
-                  }"
-                />
-                <q-menu anchor="bottom left" self="top left">
-                  <q-item
-                    v-for="(loc, index) in availableLocales"
-                    :key="index"
-                    v-ripple
-                    clickable
-                    :active="selectedLocale === loc"
-                    active-class="text-primary"
-                    @click="changeLocale(loc)"
-                  >
-                    <q-item-section>
-                      {{ loc }}
-                    </q-item-section>
-                  </q-item>
-                </q-menu>
-              </div>
-              <q-btn
-                flat
-                dense
-                round
-                :class="{
-                  'text-black': !$q.dark.isActive,
-                  'text-white': $q.dark.isActive,
-                }"
-                :icon="
-                  $q.dark.isActive
-                    ? 'mdi-white-balance-sunny'
-                    : 'mdi-moon-waning-crescent'
-                "
-                aria-label="Toggle dark mode"
-                @click="$q.dark.toggle()"
-              />
-            </div>
-          </div>
-        </q-toolbar-title>
-      </q-toolbar>
-    </q-footer>
   </q-layout>
 </template>
 
 <script setup>
 import { ref } from "vue";
-import { version } from "../../package.json";
-import { format } from "date-fns";
-import { useQuasar } from "quasar";
-import { useI18n } from "vue-i18n";
-import darkLogo from "/src/assets/softpar_logo.png";
-// import lightLogo from "/src/assets/logo_softpar_azul.png";
-
 import LeftMenuLayout from "src/components/geral/LeftMenuLayout.vue";
 
-const $q = useQuasar();
-const { availableLocales, locale } = useI18n();
-const selectedLocale = ref(locale.value);
-
 defineOptions({
   name: "MainLayout",
 });
 
-const changeLocale = (loc) => {
-  locale.value = loc;
-  selectedLocale.value = loc;
-};
-
-const year = ref(format(new Date(), "yyyy"));
 const leftDrawerOpen = ref(false);
-
-function toggleLeftDrawer() {
-  leftDrawerOpen.value = !leftDrawerOpen.value;
-}
 </script>

+ 1 - 1
src/pages/home/HomePage.vue

@@ -1,5 +1,5 @@
 <template>
-  <q-page> </q-page>
+  <div class="q-pa-md"></div>
 </template>
 
 <script setup></script>

+ 2 - 2
src/pages/users/UsersPage.vue

@@ -1,5 +1,5 @@
 <template>
-  <q-page padding>
+  <div class="q-pa-md">
     <DefaultTable
       :key="tableKey"
       :columns="columns"
@@ -13,7 +13,7 @@
       @on-row-click="onRowClick"
       @on-add-item="onAddItem"
     />
-  </q-page>
+  </div>
 </template>
 
 <script setup>