소스 검색

implement header component & harmonize layout

tripeur 4 년 전
부모
커밋
87cb34dc4e

+ 16 - 8
src/LoginPage.vue

@@ -1,8 +1,5 @@
 <template>
-  <div class="header">
-    <div class="logo"></div>
-    <a class="appname" href="/planner">BDLG planner</a>
-  </div>
+  <c-header title="BDLG Planner" titleTo="/planner" />
   <div class="container">
     <login class="login-box" />
   </div>
@@ -11,21 +8,32 @@
 <script lang="ts">
 import { defineComponent } from "vue";
 import login from "./views/Login.vue";
+import cHeader from "@/components/Header.vue";
 
 export default defineComponent({
-  components: { login },
+  components: { login, cHeader },
 });
 </script>
 <style>
 .container {
-  margin-top: 80px;
   width: 100%;
   display: flex;
   justify-content: center;
+  align-items: center;
+  height: calc(100vh - 3.5rem);
 }
 .login-box {
   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
-  padding: 8px 32px 16px;
-  min-width: 420px;
+  padding: 8px 24px 16px;
+  min-width: 95%;
+}
+@media (min-width: 600px) {
+  .login-box {
+    padding: 8px 32px 16px;
+    min-width: 420px;
+  }
+  .container {
+    max-height: 500px;
+  }
 }
 </style>

+ 17 - 20
src/PlannerApp.vue

@@ -1,24 +1,5 @@
 <template>
-  <div class="header">
-    <div class="logo" />
-    <router-link to="/planner" class="appname">BDLG planner</router-link>
-    <nav class="tabs floating">
-      <router-link class="tab" active-class="selected" to="/planner"> Accueil </router-link>
-      <router-link class="tab" active-class="selected" to="/planner/evenement">
-        Evenement
-      </router-link>
-      <router-link class="tab" active-class="selected" to="/planner/planning">Planning</router-link>
-      <router-link class="tab" active-class="selected" to="/planner/competences">
-        Gestion des compétences
-      </router-link>
-      <router-link class="tab" active-class="selected" to="/planner/benevoles">
-        Gestion des bénévoles
-      </router-link>
-      <router-link class="tab" active-class="selected" to="/planner/planningIndividuel">
-        Planning Individuel
-      </router-link>
-    </nav>
-  </div>
+  <c-header title="BDLG Planner" to-title="/planner" :tabs="tabs" />
   <div class="container">
     <router-view
       @export="exportStateToJson"
@@ -60,10 +41,20 @@ import importJsonState from "@/mixins/ImportJsonState";
 import { MutationTypes } from "@/store/Mutations";
 import dayjs from "dayjs";
 import { StateJSON } from "@/store/State";
+import Header, { HeaderLink } from "./components/Header.vue";
 
 const API_URL = process.env.VUE_APP_API_URL;
 
+const tabs: Array<HeaderLink> = [
+  { to: "/planner", name: "Accueil" },
+  { to: "/planner/evenement", name: "Evenement" },
+  { to: "/planner/planning", name: "Planning" },
+  { to: "/planner/competences", name: "Gestion des compétences" },
+  { to: "/planner/benevoles", name: "Gestion des bénévoles" },
+  { to: "/planner/planningIndividuel", name: "Planning Individuel" },
+];
 export default defineComponent({
+  components: { cHeader: Header },
   mixins: [updatePlanningVersions, importJsonState],
   data() {
     return {
@@ -71,6 +62,7 @@ export default defineComponent({
       explanation: "",
       showExplanation: false,
       lastToast: null as null | Toast,
+      tabs,
     };
   },
   mounted() {
@@ -305,6 +297,11 @@ export default defineComponent({
 </script>
 
 <style>
+.container {
+  display: flex;
+  justify-content: center;
+  margin: 8px;
+}
 .toast.action > span {
   cursor: pointer;
   color: var(--color-primary-600);

+ 3 - 5
src/PlanningPage.vue

@@ -1,8 +1,5 @@
 <template>
-  <div class="header">
-    <div class="logo" />
-    <div class="appname">BDLG planner</div>
-  </div>
+  <c-header title="BDLG Planner" />
   <div class="container">
     <div v-if="isLoading" class="loading">Chargement en cours <br /><dots /></div>
     <template v-else-if="hasData">
@@ -20,6 +17,7 @@
 import { defineComponent } from "vue";
 import Planning from "@/views/PlanningPersonnel.vue";
 import Dots from "@/components/Dots.vue";
+import cHeader from "@/components/Header.vue";
 import importJsonState from "@/mixins/ImportJsonState";
 import Toast from "./utils/Toast";
 
@@ -28,7 +26,7 @@ const uuidv4check = /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[
 
 export default defineComponent({
   mixins: [importJsonState],
-  components: { Planning, Dots },
+  components: { Planning, Dots, cHeader },
   data() {
     return { isLoading: true, hasData: false };
   },

+ 0 - 2
src/assets/css/editor-panel.css

@@ -1,8 +1,6 @@
 .editor-panel {
-  margin-top: 8px;
   padding: 12px;
   max-width: 400px;
-  width: 400px;
   box-shadow: 0 0 2px 2px var(--color-neutral-600);
   height: 100%;
 }

+ 1 - 1
src/assets/css/main.css

@@ -193,7 +193,7 @@ body {
   right: 0;
   bottom: 0;
   background: rgba(0, 0, 0, 0.5);
-  z-index: 100;
+  z-index: 1300;
 }
 .modal-content {
   background: white;

+ 2 - 0
src/components/EditeurCompetence.vue

@@ -44,12 +44,14 @@
       <checkbox
         id="competence_isPreference"
         label="Préference"
+        help="Réduit l'importance dans le score d'optimisation"
         :modelValue="competence.isPreference"
         @input="checkboxListener($event, 'isPreference')"
       />
       <checkbox
         id="competence_isTeachable"
         label="Apprenable"
+        help="Indique que cette compétence peut-être apprise"
         :modelValue="competence.isTeachable"
         @input="checkboxListener($event, 'isTeachable')"
       />

+ 132 - 0
src/components/Header.vue

@@ -0,0 +1,132 @@
+<template>
+  <div class="header">
+    <div class="logo" />
+    <router-link :to="titleTo" class="appname" v-if="titleTo">{{ title }}</router-link>
+    <div class="appname" v-else>{{ title }}</div>
+    <nav class="tabs floating show-lg">
+      <router-link
+        class="tab"
+        active-class="selected"
+        v-for="item in tabs"
+        :key="item.to"
+        :to="item.to"
+      >
+        {{ item.name }}
+      </router-link>
+    </nav>
+    <div class="floating show-sm burger" @click="showMenu = true" v-if="tabs.length > 0">
+      <i class="material-icons">menu</i>
+    </div>
+  </div>
+  <transition name="fade">
+    <div class="modal" v-show="showMenu" @click="closeModal">
+      <div class="sidenav" ref="sidenav" :class="{ in: showMenu }">
+        <nav>
+          <router-link
+            class="sidenav-elt"
+            active-class="selected"
+            v-for="item in tabs"
+            :key="item.to"
+            :to="item.to"
+            @click="showMenu = false"
+          >
+            {{ item.name }}
+          </router-link>
+        </nav>
+      </div>
+    </div>
+  </transition>
+</template>
+
+<script lang="ts">
+import { defineComponent, PropType } from "vue";
+
+export type HeaderLink = {
+  to: string;
+  name: string;
+};
+export default defineComponent({
+  props: {
+    tabs: { type: Array as PropType<Array<HeaderLink>>, default: () => [] },
+    title: String,
+    titleTo: String,
+  },
+  data() {
+    return { showMenu: false };
+  },
+  methods: {
+    closeModal(e: MouseEvent) {
+      if (!(this.$refs.sidenav as HTMLElement).contains(e.target as HTMLElement)) {
+        this.showMenu = false;
+      }
+    },
+  },
+});
+</script>
+
+<style>
+@media (max-width: 600px) {
+  .show-lg {
+    display: none !important;
+  }
+}
+@media (min-width: 600px) {
+  .show-sm {
+    display: none !important;
+  }
+}
+.fade-leave-active,
+.fade-enter-active {
+  transition: opacity 0.1s;
+}
+.fade-enter-from,
+.fade-leave-to {
+  opacity: 0;
+}
+.burger {
+  cursor: pointer;
+}
+.sidenav {
+  position: absolute;
+  top: 3.5rem;
+  left: 0;
+  bottom: 0;
+  background: #ffffff;
+  display: block;
+  width: 80%;
+  overflow-y: auto;
+}
+.fade-enter-active .sidenav,
+.fade-leave-active .sidenav {
+  transition: left 0.2s;
+  left: 0;
+}
+.fade-enter-active .sidenav {
+  transition-delay: 0.1s;
+}
+.fade-enter-from .sidenav,
+.fade-leave-to .sidenav {
+  left: -80%;
+}
+.sidenav-elt {
+  display: block;
+  padding: 16px;
+  color: var(--color-accent-400);
+  text-decoration: none;
+  position: relative;
+}
+.sidenav-elt.selected {
+  background: var(--color-accent-800);
+  color: var(--color-accent-200);
+}
+.sidenav-elt.selected:before {
+  content: "";
+  position: absolute;
+  left: 0px;
+  top: 2px;
+  bottom: 2px;
+  width: 4px;
+  background-color: var(--color-accent-400);
+  border-radius: 0 4px 4px 0;
+}
+</style>

+ 18 - 4
src/views/BenevoleManager.vue

@@ -135,12 +135,26 @@ export default defineComponent({
 <style scoped>
 .page {
   display: flex;
-  margin: 0px 10%;
-  justify-content: center;
+  flex-direction: column;
+  width: 100%;
+  max-width: 1100px;
+  gap: 16px;
 }
 .data-table {
-  margin: 8px 16px;
-  width: calc(100% - 432px);
+  width: 100%;
   height: min-content;
 }
+@media (min-width: 600px) {
+  .page {
+    flex-direction: row;
+  }
+  .data-table {
+    width: calc(100% - 432px);
+  }
+}
+@media (min-width: 1200px) {
+  .page {
+    margin-top: 32px;
+  }
+}
 </style>

+ 0 - 1
src/views/Login.vue

@@ -78,7 +78,6 @@ export default defineComponent({
   },
   mounted() {
     const param = new URLSearchParams(window.location.search);
-
     const nextPath = param.get("next") ?? "/";
     this.error = param.get("error") == "true" ?? false;
   },

+ 1 - 1
src/views/Planning.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="container">
+  <div style="display: flex">
     <div class="timeline">
       <div class="timelime-control">
         <h1>Planning global de l'événement</h1>

+ 1 - 1
src/views/PlanningPersonnel.vue

@@ -62,7 +62,7 @@ export default defineComponent({
     };
   },
   watch: {
-    benevoleId(val) {
+    benevoleId() {
       this.updateCurrentBenevole();
     },
   },