Browse Source

fully working menu and tabs

horanchikk 2 years ago
parent
commit
b6026d0db3

+ 6 - 7
src/App.vue

@@ -1,26 +1,25 @@
 <template>
-  <main
-    class="w-screen h-screen flex flex-col text-black font-sans"
-  >
+  <main class="w-screen h-screen flex flex-col text-black font-sans">
     <div class="bg-white">
       <Header />
     </div>
     <div class="flex-auto flex bg-black bg-opacity-10">
       <Transition name="nav" mode="out-in">
-      <Menu v-if="useUi().showNav" />
-    </Transition>
+        <Menu v-if="useUi().showNav" />
+      </Transition>
       <section class="flex-auto flex flex-col gap-5 py-4 px-8">
         <Tabs />
         <div class="flex-auto">
           <router-view />
         </div>
-      </section></div>
+      </section>
+    </div>
   </main>
 </template>
 
 <script setup lang="ts">
 import Menu from "./layouts/Menu.vue";
 import Tabs from "./layouts/Tabs.vue";
-import Header from "./layouts/Header.vue"
+import Header from "./layouts/Header.vue";
 import { useUi } from "@/stores/useUi";
 </script>

+ 18 - 3
src/layouts/Header.vue

@@ -1,8 +1,23 @@
 <template>
-  <div class="w-full h-10">
-w
+  <div class="w-full h-10 flex items-center px-4">
+    <svg
+      xmlns="http://www.w3.org/2000/svg"
+      width="30px"
+      height="30px"
+      viewBox="0 0 20 20"
+      class="cursor-pointer select-none"
+      @click="useUi().showNav = !useUi().showNav"
+    >
+      <path
+        fill="#2563EB"
+        fill-rule="evenodd"
+        d="M2 4.75A.75.75 0 0 1 2.75 4h14.5a.75.75 0 0 1 0 1.5H2.75A.75.75 0 0 1 2 4.75ZM2 10a.75.75 0 0 1 .75-.75h14.5a.75.75 0 0 1 0 1.5H2.75A.75.75 0 0 1 2 10Zm0 5.25a.75.75 0 0 1 .75-.75h14.5a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1-.75-.75Z"
+        clip-rule="evenodd"
+      />
+    </svg>
   </div>
 </template>
 
 <script setup lang="ts">
-</script>
+import { useUi } from "@/stores/useUi";
+</script>

+ 50 - 10
src/layouts/Menu.vue

@@ -1,24 +1,64 @@
 <template>
-  <div class="w-56 h-full bg-black menuBack text-white">
-    <div v-for="item in menu" :key="menu.indexOf(item)" class="text-center cursor-default">
-      {{ item.name }}
+  <div class="w-56 h-full p-5 bg-black menuBack text-xl overflow-x-scroll">
+    <div
+      v-for="item in menu"
+      :key="menu.indexOf(item)"
+      :class="`text-left cursor-pointer ${
+        item.link !== $route.path ? 'text-white' : 'text-blue-300'
+      } hover:opacity-70 active:opacity-60 transition-all`"
+    >
+      <p
+        v-if="item.link !== $route.path"
+        @click="
+          $router.push(item.link);
+          ui.tabs.find(({ link }) => link === item.link) === undefined
+            ? ui.tabs.push({
+                name: item.name,
+                link: item.link,
+                removable: false,
+              })
+            : undefined;
+          ui.updateTabs();
+        "
+      >
+        {{ item.name }}
+      </p>
+      <p v-else>{{ item.name }}</p>
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue';
-import type { Ref } from 'vue';
+import { ref } from "vue";
+import { useUi } from "@/stores/useUi";
+import type { Ref } from "vue";
 
 interface menuItem {
-  name: string
-  link: string
+  name: string;
+  link: string;
 }
 
+const ui = useUi();
 const menu: Ref<menuItem[]> = ref([
   {
-    name: "Статистика",
+    name: "Home",
+    link: "/",
+  },
+  {
+    name: "Stats",
     link: "/stats",
   },
-])
-</script>
+  {
+    name: "Settings",
+    link: "/settings",
+  },
+  {
+    name: "Components",
+    link: "/components",
+  },
+  {
+    name: "System",
+    link: "/system",
+  },
+]);
+</script>

+ 44 - 53
src/layouts/Tabs.vue

@@ -1,64 +1,55 @@
 <template>
   <div class="w-full h-12 flex gap-5 overflow-y-hidden overflow-x-scroll">
-    <TransitionGroup name="tabs" mode="in-out">
+    <TransitionGroup name="tabs" mode="out-in">
       <!-- todo: better animation, when closing tabs -->
-      <div
-        v-for="tab in tabs"
-        :key="tabs.indexOf(tab)"
-        class="w-40"
-      >
-        <router-link :to="tab.link">
-          <div class="px-5 py-1 flex items-center justify-between cursor-pointer rounded-md bg-blue-600 select-none text-white bg-opacity-80 hover:bg-opacity-70 transition-all overflow-visible">
-            <div>{{ tab.name }}</div>
-            <div
-                class="hover:opacity-70 active:opacity-40 cursor-pointer transition-all"
-                v-if="tab.removable"
-                @click="tabs.splice(tabs.indexOf(tab), 1)"
-            >
-              <svg xmlns="http://www.w3.org/2000/svg" height="24" width="24">
-                <path
-                    d="M6.4 19 5 17.6l5.6-5.6L5 6.4 6.4 5l5.6 5.6L17.6 5 19 6.4 13.4 12l5.6 5.6-1.4 1.4-5.6-5.6Z"
-                    fill="#ffffff"
-                />
-              </svg>
-            </div>
+      <div v-for="tab in ui.tabs" :key="ui.tabs.indexOf(tab)" class="w-40">
+        <div
+          v-if="tab.link !== $route.path"
+          class="px-5 py-1 flex items-center justify-between rounded-md bg-blue-700 select-none text-white bg-opacity-80 hover:bg-opacity-70 transition-all overflow-visible"
+        >
+          <div
+            class="cursor-pointer"
+            @click="
+              $router.push(tab.link);
+              ui.updateTabs();
+              tab.removable = false;
+            "
+          >
+            {{ tab.name }}
           </div>
-        </router-link>
+          <div
+            class="hover:opacity-70 active:opacity-40 cursor-pointer transition-all"
+            @click="ui.tabs.splice(ui.tabs.indexOf(tab), 1)"
+          >
+            <svg xmlns="http://www.w3.org/2000/svg" height="24" width="24">
+              <path
+                d="M6.4 19 5 17.6l5.6-5.6L5 6.4 6.4 5l5.6 5.6L17.6 5 19 6.4 13.4 12l5.6 5.6-1.4 1.4-5.6-5.6Z"
+                fill="#ffffff"
+              />
+            </svg>
+          </div>
+        </div>
+        <div
+          class="px-5 py-1 flex items-center justify-between rounded-md bg-blue-700 select-none text-white bg-opacity-80 hover:bg-opacity-70 transition-all overflow-visible"
+          v-else
+        >
+          <div
+            class="cursor-pointer"
+            @click="
+              $router.push(tab.link);
+              ui.updateTabs();
+              tab.removable = false;
+            "
+          >
+            {{ tab.name }}
+          </div>
+        </div>
       </div>
     </TransitionGroup>
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref } from "vue";
-import type { Ref } from "vue";
-
-interface OpenedTabs {
-  name: string
-  link: string
-  removable: boolean
-}
-
-const tabs: Ref<OpenedTabs[]> = ref([
-  {
-    name: "Home",
-    link: "/",
-    removable: false,
-  },
-  {
-    name: "Components",
-    link: "/components",
-    removable: true,
-  },
-  {
-    name: "Stats",
-    link: "/stats",
-    removable: true,
-  },
-  {
-    name: "System",
-    link: "/system",
-    removable: true,
-  }
-]);
+import { useUi } from "@/stores/useUi";
+const ui = useUi();
 </script>

+ 20 - 1
src/router/index.ts

@@ -1,14 +1,33 @@
 import { createRouter, createWebHistory } from "vue-router";
+
 import HomeView from "../views/HomeView.vue";
+import ComponentsView from "../views/ComponentsView.vue";
+import StatsView from "../views/StatsView.vue";
+import SystemView from "../views/SystemView.vue";
 
 const router = createRouter({
   history: createWebHistory(import.meta.env.BASE_URL),
   routes: [
     {
       path: "/",
-      name: "home",
+      name: "Home",
       component: HomeView,
     },
+    {
+      path: "/components",
+      name: "Components",
+      component: ComponentsView,
+    },
+    {
+      path: "/stats",
+      name: "Stats",
+      component: StatsView,
+    },
+    {
+      path: "/system",
+      name: "System",
+      component: SystemView,
+    },
   ],
 });
 

+ 37 - 2
src/stores/useUi.ts

@@ -3,7 +3,42 @@ import type { Ref } from "vue";
 import { defineStore } from "pinia";
 
 export const useUi = defineStore("ui", () => {
-  const showNav: Ref<boolean> = ref(false)
+  const showNav: Ref<boolean> = ref(true);
 
-  return {showNav}
+  interface OpenedTabs {
+    name: string;
+    link: string;
+    removable: boolean;
+  }
+
+  const tabs: Ref<OpenedTabs[]> = ref([
+    {
+      name: "Home",
+      link: "/",
+      removable: false,
+    },
+    {
+      name: "Components",
+      link: "/components",
+      removable: true,
+    },
+    {
+      name: "Stats",
+      link: "/stats",
+      removable: true,
+    },
+    {
+      name: "System",
+      link: "/system",
+      removable: true,
+    },
+  ]);
+
+  function updateTabs() {
+    for (let tab in tabs.value) {
+      tabs.value[tab].removable = true;
+    }
+  }
+
+  return { showNav, tabs, updateTabs };
 });

+ 4 - 4
src/style.css

@@ -4,7 +4,7 @@
 
 .tabs-enter-active,
 .tabs-leave-active {
-  transition: all .5s;
+  transition: all 0.5s;
   max-width: 100px;
 }
 
@@ -21,7 +21,7 @@
 
 .nav-enter-active,
 .nav-leave-active {
-  transition: all .4s;
+  transition: all 0.4s;
   max-width: 1000px;
 }
 
@@ -36,5 +36,5 @@
 }
 
 .menuBack {
-  background: linear-gradient(360deg, yellowgreen, green);
-}
+  background: linear-gradient(360deg, yellow, purple);
+}

+ 9 - 0
src/views/ComponentsView.vue

@@ -0,0 +1,9 @@
+<template>
+  <div
+    class="w-full h-full flex items-center justify-center text-2xl font-mono font-bold"
+  >
+    COMPONENTS
+  </div>
+</template>
+
+<style scoped></style>

+ 4 - 7
src/views/HomeView.vue

@@ -1,12 +1,9 @@
 <template>
-  <div>
-    <button @click="useUi().showNav = !useUi().showNav">show</button>
+  <div
+    class="w-full h-full flex items-center justify-center text-2xl font-mono font-bold"
+  >
+    HOME
   </div>
 </template>
 
-<script setup lang="ts">
-import { useUi } from "@/stores/useUi";
-
-</script>
-
 <style scoped></style>

+ 3 - 0
src/views/SettingsView.vue

@@ -0,0 +1,3 @@
+<template>
+  <div class="w-full h-full flex items-center justify-center">settings</div>
+</template>

+ 9 - 0
src/views/StatsView.vue

@@ -0,0 +1,9 @@
+<template>
+  <div
+    class="w-full h-full flex items-center justify-center text-2xl font-mono font-bold"
+  >
+    STATS
+  </div>
+</template>
+
+<style scoped></style>

+ 9 - 0
src/views/SystemView.vue

@@ -0,0 +1,9 @@
+<template>
+  <div
+    class="w-full h-full flex items-center justify-center text-2xl font-mono font-bold"
+  >
+    SYSTEM
+  </div>
+</template>
+
+<style scoped></style>