changeset 1204:ddfdf440da24

made searchbar contextual if bottlenecks are open search bar refers to that list if imports are open search bar is hidden
author Markus Kottlaender <markus@intevation.de>
date Mon, 19 Nov 2018 11:23:00 +0100
parents 37889ae85133
children 5ba14f7f5bdc
files client/src/App.vue client/src/application/Search.vue client/src/application/Sidebar.vue client/src/application/assets/application.sass client/src/bottlenecks/Bottlenecks.vue client/src/drawtool/Drawtool.vue client/src/fairway/Fairwayprofile.vue client/src/imports/Imports.vue client/src/store/application.js
diffstat 9 files changed, 202 insertions(+), 147 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/App.vue	Mon Nov 19 09:09:27 2018 +0100
+++ b/client/src/App.vue	Mon Nov 19 11:23:00 2018 +0100
@@ -2,13 +2,19 @@
     <div id="app" class="main">
         <div v-if="isAuthenticated" class="d-flex flex-column userinterface">
             <div class="topcontainer">
-                <div class="topbar d-flex flex-row">
-                    <Sidebar :routeName="routeName"></Sidebar>
-                    <Bottlenecks v-if="routeName == 'mainview'"></Bottlenecks>
-                    <Imports v-if="routeName == 'mainview'"></Imports>
-                    <Search v-if="routeName == 'mainview'"></Search>
-                    <Layers v-if="routeName == 'mainview'"></Layers>
-                    <Identify v-if="routeName == 'mainview'"></Identify>
+                <div class="topbar d-flex">
+                    <div class="mr-auto d-flex">
+                        <Sidebar :routeName="routeName"></Sidebar>
+                        <div class="d-flex flex-column" style="max-width: 600px;">
+                            <Search v-if="routeName == 'mainview'"></Search>
+                            <Bottlenecks v-if="routeName == 'mainview'"></Bottlenecks>
+                            <Imports v-if="routeName == 'mainview'"></Imports>
+                        </div>
+                    </div>
+                    <div class="ml-auto d-flex">
+                        <Layers v-if="routeName == 'mainview'"></Layers>
+                        <Identify v-if="routeName == 'mainview'"></Identify>
+                    </div>
                 </div>
             </div>
             <div class="flex-fill"></div>
--- a/client/src/application/Search.vue	Mon Nov 19 09:09:27 2018 +0100
+++ b/client/src/application/Search.vue	Mon Nov 19 11:23:00 2018 +0100
@@ -1,6 +1,6 @@
 <template>
     <div :class="searchbarContainerStyle">
-        <div class="input-group-prepend shadow">
+        <div class="input-group-prepend">
             <span @click="toggleSearchbar" :class="searchButtonStyle" for="search">
                 <i class="fa fa-search d-print-none"></i>
             </span>
@@ -12,9 +12,9 @@
                 id="search"
                 v-model="searchQuery"
                 type="text"
-                class="form-control ui-element search searchbar d-print-none"
+                :class="searchInputStyle"
             >
-            <ul v-if="showSearchbar && searchResults !== null " class="list-group d-print-none">
+            <ul v-if="showSearchbar && searchResults !== null && !showBottlenecks" class="list-group d-print-none">
                 <li v-for="entry of searchResults" :key="entry.name" class="list-group-item">
                     <a href="#" @click.prevent="moveToSearchResult(entry)">{{entry.name}}</a>
                 </li>
@@ -25,25 +25,30 @@
 
 <style lang="sass" scoped>
   .searchcontainer
+    margin-left: $offset
     height: $icon-height
-    border-radius: 0.25rem
 
   .searchbar-expanded
-    width: $searchbar-width !important
     .searchbar
       border-top-left-radius: 0 !important
       border-bottom-left-radius: 0 !important
 
-
   .searchbar-collapsed
     width: $icon-width !important
     transition: $transition-fast
 
   .searchbar
     height: $icon-height !important
+    box-shadow: none !important
+    &.rounded-top-right
+      border-radius: 0 !important
+      border-top-right-radius: 0.25rem !important
 
   .searchlabel
     background-color: white !important
+    &.rounded-top-left
+      border-radius: 0 !important
+      border-top-left-radius: 0.25rem !important
 
   .input-group-text
     height: $icon-height
@@ -51,6 +56,8 @@
 
   .list-group
     pointer-events: auto
+    max-height: 40vh
+    overflow: auto
 </style>
 
 <script>
@@ -80,14 +87,25 @@
   name: "search",
   data() {
     return {
-      searchQuery: "",
       searchQueryIsDirty: false,
       searchResults: null,
       isSearching: false
     };
   },
   computed: {
-    ...mapState("application", ["showSearchbar"]),
+    ...mapState("application", [
+      "showSearchbar",
+      "showBottlenecks",
+      "showImportSoundingResults"
+    ]),
+    searchQuery: {
+      get() {
+        return this.$store.state.application.searchQuery;
+      },
+      set(value) {
+        this.$store.commit("application/searchQuery", value);
+      }
+    },
     searchIndicator: function() {
       if (this.isSearching) {
         return "⟳";
@@ -99,19 +117,28 @@
     },
     searchbarContainerStyle() {
       return [
-        "d-flex input-group searchcontainer",
+        "input-group searchcontainer shadow",
         {
           "searchbar-collapsed": !this.showSearchbar,
-          "searchbar-expanded": this.showSearchbar
+          "searchbar-expanded": this.showSearchbar,
+          "d-flex": !this.showImportSoundingResults,
+          "d-none": this.showImportSoundingResults
         }
       ];
     },
+    searchInputStyle() {
+      return [
+        "form-control ui-element search searchbar d-print-none border-0",
+        { "rounded-top-right": this.showSearchbar && this.showBottlenecks }
+      ];
+    },
     searchButtonStyle() {
       return [
-        "ui-element input-group-text p-0 d-flex justify-content-center searchlabel d-print-none",
+        "ui-element input-group-text p-0 d-flex border-0 justify-content-center searchlabel d-print-none",
         {
           rounded: !this.showSearchbar,
-          "rounded-left": this.showSearchbar
+          "rounded-left": this.showSearchbar,
+          "rounded-top-left": this.showSearchbar && this.showBottlenecks
         }
       ];
     }
@@ -181,10 +208,12 @@
       this.toggleSearchbar();
     },
     toggleSearchbar() {
-      if (!this.showSearchbar) {
-        setTimeout(setFocus, 300);
+      if (!this.showBottlenecks) {
+        if (!this.showSearchbar) {
+          setTimeout(setFocus, 300);
+        }
+        this.$store.commit("application/showSearchbar", !this.showSearchbar);
       }
-      this.$store.commit("application/showSearchbar", !this.showSearchbar);
     }
   }
 };
--- a/client/src/application/Sidebar.vue	Mon Nov 19 09:09:27 2018 +0100
+++ b/client/src/application/Sidebar.vue	Mon Nov 19 11:23:00 2018 +0100
@@ -15,7 +15,7 @@
                     class="text-body d-flex flex-row nav-link"
                     v-if="routeName == 'mainview'"
                     href="#"
-                    @click="$store.commit('application/showBottlenecks', !showBottlenecks);"
+                    @click="toggleBottlenecks"
                 >Bottlenecks</a>
                 <div v-if="isSysAdmin">
                     <hr>
@@ -30,7 +30,7 @@
                         <a
                             href="#"
                             class="text-body"
-                            @click="$store.commit('application/showImportSoundingResults', !showImportSoundingResults);"
+                            @click="toggleImportSoundingResults"
                         >Import soundingresults</a>
                     </div>
                     <!-- <router-link class="text-body d-flex flex-row nav-link" to="imports">
@@ -115,6 +115,18 @@
       this.$store.commit("application/showUsermenu", false);
       this.$store.commit("application/showSplitscreen", false);
       this.$router.push("/login");
+    },
+    toggleBottlenecks() {
+      this.$store.commit("application/showBottlenecks", !this.showBottlenecks);
+      this.$store.commit("application/showImportSoundingResults", false);
+      this.$store.commit("application/showSearchbar", this.showBottlenecks);
+    },
+    toggleImportSoundingResults() {
+      this.$store.commit(
+        "application/showImportSoundingResults",
+        !this.showImportSoundingResults
+      );
+      this.$store.commit("application/showBottlenecks", false);
     }
   }
 };
--- a/client/src/application/assets/application.sass	Mon Nov 19 09:09:27 2018 +0100
+++ b/client/src/application/assets/application.sass	Mon Nov 19 11:23:00 2018 +0100
@@ -23,7 +23,6 @@
 $identify-height: 20rem
 $identify-width: 20rem
 $offset: 1rem
-$searchbar-width: 50vw
 $sidebar-height: 32rem
 $sidebar-width: 15rem
 $slight-transparent: 0.96
--- a/client/src/bottlenecks/Bottlenecks.vue	Mon Nov 19 09:09:27 2018 +0100
+++ b/client/src/bottlenecks/Bottlenecks.vue	Mon Nov 19 11:23:00 2018 +0100
@@ -1,13 +1,12 @@
 <template>
     <div :class="bottlenecksStyle">
-        <div @click="$store.commit('application/showBottlenecks', !showBottlenecks);" class="ui-element close-bottlenecks">
+        <div @click="closeBottlenecks" class="ui-element close-bottlenecks">
             <i class="fa fa-close"></i>
         </div>
 
         <h4>Bottlenecks</h4>
         <hr class="mb-0">
-        <input type="text" v-model="search" placeholder="Search Bottleneck..." class="border-0 w-100 p-2" />
-        <div class="row p-2 border-top text-left small">
+        <div class="row p-2 text-left small">
             <div class="col-5">
                 <a href="#" @click="sortBy('name')" class="sort-link">Name</a>
                 <i :class="sortClass" v-if="sortColumn === 'name'"></i>
@@ -73,7 +72,6 @@
   name: "bottlenecks",
   data() {
     return {
-      search: "",
       sortColumn: "name",
       sortDirection: "ASC",
       openBottleneck: null,
@@ -81,12 +79,16 @@
     };
   },
   computed: {
-    ...mapState("application", ["showBottlenecks", "showSidebar"]),
+    ...mapState("application", [
+      "showBottlenecks",
+      "showSidebar",
+      "searchQuery"
+    ]),
     ...mapState("bottlenecks", ["bottlenecks"]),
     ...mapState("map", ["openLayersMap"]),
     bottlenecksStyle() {
       return [
-        "ui-element shadow bottlenecks",
+        "ui-element shadow bottlenecks border-top",
         {
           bottleneckscollapsed: !this.showBottlenecks,
           bottlenecksextended: this.showBottlenecks
@@ -109,7 +111,7 @@
         .filter(bn => {
           return bn.properties.name
             .toLowerCase()
-            .includes(this.search.toLowerCase());
+            .includes(this.searchQuery.toLowerCase());
         })
         .sort((bnA, bnB) => {
           switch (this.sortColumn) {
@@ -194,6 +196,10 @@
           });
       }
     },
+    closeBottlenecks() {
+      this.$store.commit("application/showBottlenecks", false);
+      this.$store.commit("application/showSearchbar", false);
+    },
     displayCurrentSurvey(current) {
       return current ? current.substr(0, current.length - 1) : "";
     },
@@ -213,7 +219,8 @@
   background-color: #ffffff
   padding-top: $offset
   opacity: $slight-transparent
-  border-radius: $border-radius
+  border-bottom-left-radius: $border-radius
+  border-bottom-right-radius: $border-radius
   transition: left 0.3s ease
   overflow: hidden
   background: #fff
--- a/client/src/drawtool/Drawtool.vue	Mon Nov 19 09:09:27 2018 +0100
+++ b/client/src/drawtool/Drawtool.vue	Mon Nov 19 11:23:00 2018 +0100
@@ -150,12 +150,12 @@
           stroke: new Stroke({
             color: "#444",
             width: 2,
-            lineDash: [7,7]
+            lineDash: [7, 7]
           }),
           image: new Circle({
             fill: new Fill({ color: "#333" }),
             stroke: new Stroke({ color: "#fff", width: 1.5 }),
-            radius: 6,
+            radius: 6
           })
         })
       });
--- a/client/src/fairway/Fairwayprofile.vue	Mon Nov 19 09:09:27 2018 +0100
+++ b/client/src/fairway/Fairwayprofile.vue	Mon Nov 19 11:23:00 2018 +0100
@@ -532,7 +532,7 @@
     },
     applyCoordinates(coordinates) {
       // allow only numbers
-      coordinates = coordinates.filter(c => Number(c) === c)
+      coordinates = coordinates.filter(c => Number(c) === c);
       if (coordinates.length === 4) {
         // draw line on map
         const cutLayer = this.getLayerByName("Cut Tool");
@@ -550,7 +550,8 @@
       } else {
         displayError({
           title: "Invalid input",
-          message: "Please enter correct coordinates in the format: Lat,Lon,Lat,Lon"
+          message:
+            "Please enter correct coordinates in the format: Lat,Lon,Lat,Lon"
         });
       }
     },
--- a/client/src/imports/Imports.vue	Mon Nov 19 09:09:27 2018 +0100
+++ b/client/src/imports/Imports.vue	Mon Nov 19 11:23:00 2018 +0100
@@ -1,87 +1,79 @@
 <template>
-    <div v-if="showImportSoundingResults">
-        <div class="imports shadow d-flex content flex-column ui-element">
-            <div class="card importcard">
-                <div class="card-body importcardbody">
-                    <div
-                        @click="$store.commit('application/showImportSoundingResults', !showImportSoundingResults);"
-                        class="ui-element close-showImportSoundingResults"
+    <div :class="importStyle">
+        <div @click="$store.commit('application/showImportSoundingResults', false);" class="ui-element close-imports">
+            <i class="fa fa-close"></i>
+        </div>
+
+        <h4>Import soundingresults</h4>
+        <hr class="mb-0">
+        <div class="p-3">
+            <div class="d-flex flex-row input-group mb-4">
+                <div class="">
+                    <label
+                        for="bottleneck"
+                        class="label-text"
+                        id="bottlenecklabel"
+                    >Bottleneck</label>
+                </div>
+                <input
+                    id="bottleneck"
+                    type="text"
+                    class="form-control"
+                    placeholder="Name of Bottleneck"
+                    aria-label="bottleneck"
+                    aria-describedby="bottlenecklabel"
+                    v-model="bottleneck"
+                >
+            </div>
+            <div class="d-flex flex-row input-group mb-4">
+                <div class="">
+                    <label class="label-text" for="importdate" id="importdatelabel">Date</label>
+                </div>
+                <input
+                    id="importdate"
+                    type="date"
+                    class="form-control"
+                    placeholder="Date of import"
+                    aria-label="bottleneck"
+                    aria-describedby="bottlenecklabel"
+                    v-model="importDate"
+                >
+            </div>
+            <div class="d-flex flex-row input-group mb-4">
+                <div class="">
+                    <label class="label-text" for="depthreference">Depth reference</label>
+                </div>
+                <select v-model="depthReference" class="custom-select" id="depthreference">
+                    <option
+                        v-for="option in this.$options.depthReferenceOptions"
+                        :key="option"
+                    >{{option}}</option>
+                </select>
+            </div>
+            <div class="d-flex flex-row input-group mb-4">
+                <div class="custom-file">
+                    <input
+                        type="file"
+                        @change="fileSelected"
+                        class="custom-file-input"
+                        id="uploadFile"
                     >
-                        <i class="fa fa-close"></i>
-                    </div>
-                    <div class="card-title mb-4 headline">
-                        <h4>Import soundingresults</h4>
-                        <hr>
-                    </div>
-                    <div class="d-flex flex-row input-group mb-4">
-                        <div class="">
-                            <label
-                                for="bottleneck"
-                                class="label-text"
-                                id="bottlenecklabel"
-                            >Bottleneck</label>
-                        </div>
-                        <input
-                            id="bottleneck"
-                            type="text"
-                            class="form-control"
-                            placeholder="Name of Bottleneck"
-                            aria-label="bottleneck"
-                            aria-describedby="bottlenecklabel"
-                            v-model="bottleneck"
-                        >
-                    </div>
-                    <div class="d-flex flex-row input-group mb-4">
-                        <div class="">
-                            <label class="label-text" for="importdate" id="importdatelabel">Date</label>
-                        </div>
-                        <input
-                            id="importdate"
-                            type="date"
-                            class="form-control"
-                            placeholder="Date of import"
-                            aria-label="bottleneck"
-                            aria-describedby="bottlenecklabel"
-                            v-model="importDate"
-                        >
-                    </div>
-                    <div class="d-flex flex-row input-group mb-5">
-                        <div class="">
-                            <label class="label-text" for="depthreference">Depth reference</label>
-                        </div>
-                        <select v-model="depthReference" class="custom-select" id="depthreference">
-                            <option
-                                v-for="option in this.$options.depthReferenceOptions"
-                                :key="option"
-                            >{{option}}</option>
-                        </select>
-                    </div>
-                    <div class="d-flex flex-row input-group mb-5">
-                        <div class="custom-file">
-                            <input
-                                type="file"
-                                @change="fileSelected"
-                                class="custom-file-input"
-                                id="uploadFile"
-                            >
-                            <label class="custom-file-label" for="uploadFile">{{uploadLabel}}</label>
-                        </div>
-                    </div>
-                    <div class="downloadbtn">
-                        <a
-                            download="meta.json"
-                            :href="dataLink "
-                            class="btn btn-outline-info"
-                        >Generate Meta.json</a>
-                        <button
-                            :disabled="disableUpload"
-                            @click="submitUpload"
-                            class="btn btn-info"
-                            type="button"
-                        >Upload!</button>
-                    </div>
+                    <label class="custom-file-label" for="uploadFile">{{uploadLabel}}</label>
                 </div>
             </div>
+            <div class="downloadbtn text-right">
+                <a
+                    download="meta.json"
+                    :href="dataLink "
+                    class="btn btn-outline-info mr-2"
+                >Generate Meta.json</a>
+                <button
+                    :disabled="disableUpload"
+                    @click="submitUpload"
+                    class="btn btn-info"
+                    type="button"
+                >Upload!</button>
+            </div>
         </div>
     </div>
 </template>
@@ -138,6 +130,15 @@
   },
   computed: {
     ...mapState("application", ["showImportSoundingResults"]),
+    importStyle() {
+      return [
+        "ui-element shadow imports",
+        {
+          importscollapsed: !this.showImportSoundingResults,
+          importsextended: this.showImportSoundingResults
+        }
+      ];
+    },
     dataLink() {
       return (
         "data:text/json;charset=utf-8," +
@@ -178,7 +179,27 @@
 </script>
 
 <style lang="sass" scoped>
-.close-showImportSoundingResults
+.imports
+  position: relative
+  background-color: #ffffff
+  padding-top: $offset
+  opacity: $slight-transparent
+  border-radius: $border-radius
+  transition: left 0.3s ease
+  overflow: hidden
+  background: #fff
+  margin-left: $offset
+  margin-top: -$offset
+
+.importscollapsed
+  width: 0
+  height: 0
+  transition: $transition-fast
+
+.importsextended
+  min-width: 600px
+
+.close-imports
   position: absolute
   z-index: 2
   right: 0
@@ -186,37 +207,13 @@
   border-radius: $border-radius
   height: $icon-width
   width: $icon-height
-  
+  display: none
+
+.importsextended .close-imports
+  display: block
+
 .label-text
   width: 10rem
   text-align: left
   line-height: 2.25rem
-
-.importcard
-  height: 100%
-  
-.importcardbody
-  position: relative
-  height: 100%
-  width: 90%
-  margin-left: auto
-  margin-right: auto
-  
-.imports
-  position: relative
-  background-color: white
-  width: 30rem
-  height: 28rem
-  margin-left: auto
-  margin-right: auto
-  border-radius: $border-radius
-  opacity: $slight-transparent
-  
-.downloadbtn
-  position: absolute
-  right: $offset
-  bottom: $offset
-
-.downloadbtn a
-  margin-right: $offset
 </style>
--- a/client/src/store/application.js	Mon Nov 19 09:09:27 2018 +0100
+++ b/client/src/store/application.js	Mon Nov 19 11:23:00 2018 +0100
@@ -31,6 +31,7 @@
     showPdfTool: false,
     showImportSoundingResults: false,
     countries: ["AT", "SK", "HU", "HR", "RS", "BiH", "BG", "RO", "UA"],
+    searchQuery: "",
     version
   },
   getters: {
@@ -77,6 +78,9 @@
     },
     showImportSoundingResults: (state, show) => {
       state.showImportSoundingResults = show;
+    },
+    searchQuery: (state, searchQuery) => {
+      state.searchQuery = searchQuery;
     }
   }
 };