Parcourir la source

add NodePreview & NodeViewChildListGroup in Library

axolotle il y a 3 ans
Parent
commit
e15fb85761

+ 18 - 1
src/pages/library/LibraryList.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="library-list">
-    <div class="library-list-container">
+    <div class="library-list-container" @click="onContainerClick">
       <div v-for="(parents, char) in filteredNodes" :key="char">
         <h3>{{ char }}</h3>
 
@@ -9,7 +9,10 @@
             v-for="parent in parents" :key="parent.id"
             :node="parent"
             mode="card"
+            @click.native.capture="previewNode = parent"
+            :preview="previewNode === parent"
             @open-node="$emit('open-node', $event)"
+            @open-child="$emit('open-node', { parentId: parent.id, ...$event })"
           />
         </div>
       </div>
@@ -31,6 +34,12 @@ export default {
     NodeView
   },
 
+  data () {
+    return {
+      previewNode: null
+    }
+  },
+
   computed: {
     ...mapGetters(['orderedTextsDepart', 'search', 'tags']),
 
@@ -50,6 +59,14 @@ export default {
     }
   },
 
+  methods: {
+    onContainerClick (e) {
+      if (!e.target.classList.contains('node-view')) {
+        this.previewNode = null
+      }
+    }
+  },
+
   created () {
     this.$store.dispatch('INIT_LIBRARY_LIST')
   }

+ 40 - 9
src/pages/library/LibraryMap.vue

@@ -6,13 +6,21 @@
         :style="`--x: ${node.x}px; --y: ${node.y}px; --r: ${node.rotate}deg;`"
       >
         <node-view
+          :id="'preview-node-' + node.data.id"
+          :class="{ 'hidden': previewNode === node.data }"
           :node="node.data"
           mode="card"
-          @open-node="onOpen(node.data)"
           :hidden="node.hidden"
+          @click.native="onNodeClick(node.data)"
         />
       </foreignObject>
     </map-zoom>
+
+    <node-preview-zone
+      v-if="dataNodes"
+      v-model="previewNode" :nodes="dataNodes"
+      @open-node="onPreviewNodeClick"
+    />
   </b-overlay>
 </template>
 
@@ -21,8 +29,8 @@ import { randomUniform } from 'd3'
 import { forceSimulation, forceCollide, forceManyBody } from 'd3-force'
 import { mapGetters } from 'vuex'
 
-import { searchInNode, tagsInNode } from '@/store/utils'
-import { MapZoom } from '@/components/layouts'
+import { searchInNode, tagsInNode, getRelation } from '@/store/utils'
+import { MapZoom, NodePreviewZone } from '@/components/layouts'
 import { NodeView } from '@/components/nodes'
 
 
@@ -31,13 +39,15 @@ export default {
 
   components: {
     MapZoom,
+    NodePreviewZone,
     NodeView
   },
 
   data () {
     return {
       simulation: forceSimulation(),
-      nodes: undefined
+      nodes: undefined,
+      previewNode: null
     }
   },
 
@@ -53,16 +63,27 @@ export default {
         })
       })
       return this.nodes
+    },
+
+    dataNodes () {
+      if (!this.nodes) return
+      return this.nodes.map(node => node.data)
     }
   },
 
   methods: {
     onOpen (node) {
-      if (node.parents && node.parents.length) {
-        this.$emit('open-node', { parentId: node.parents[0].id, childId: node.id })
-      } else {
-        this.$emit('open-node', { parentId: node.id })
-      }
+      this.$parent.$emit('open-node', getRelation(node))
+    },
+
+    onNodeClick (node) {
+      this.previewNode = node
+      this.$root.$emit('bv::show::popover', 'preview-node-' + node.id)
+    },
+
+    onPreviewNodeClick (ids) {
+      this.$root.$emit('bv::hide::popover', 'preview-node-' + this.previewNode.id)
+      this.$emit('open-node', ids)
     }
   },
 
@@ -93,4 +114,14 @@ foreignObject {
     cursor: pointer;
   }
 }
+
+.node-view.hidden {
+  border: $line;
+  border-style: dashed;
+  background-color: transparent;
+
+  ::v-deep .node-view-wrapper {
+    opacity: 0;
+  }
+}
 </style>

+ 39 - 20
src/pages/library/LibraryTree.vue

@@ -14,11 +14,15 @@
         :cx="node.x"
         :cy="node.y"
         class="svg-dot"
+        :id="'preview-node-' + node.data.id"
         :class="['svg-dot-' + node.data.variant, { 'origin': node.parent === null }]"
         tabindex="0"
-        @click="onNodeClick(node.data)"
-        @keyup.enter="onNodeClick(node.data)"
+        @focus="activeNode = node"
         @mouseenter="activeNode = node"
+        @mouseleave="activeNode = null"
+        @blur="activeNode = null"
+        @click.stop="onNodeClick(node.data)"
+        @keyup.enter="onNodeClick(node.data)"
       />
 
       <g>
@@ -30,20 +34,20 @@
         >
           <dot-button
             :variant="activeNode.data.variant"
-            class="active"
+            active hovered
             @click="onNodeClick(activeNode.data)"
-            @mouseleave="activeNode = null"
           >
-            <template v-if="activeNode.data.variant !== 'depart'">
+            <template v-if="activeNode.data.type === 'prod'">
               {{ $t('variants.' + activeNode.data.variant) }}<br>
             </template>
-            {{ toCommaList(activeNode.data.authors) }},<br>
-            <span v-if="activeNode.data.preTitle" v-html="trim(activeNode.data.preTitle) + ','" />
-            <span v-html="trim(activeNode.data.title) || '<em>pas de titre ital</em>'" />
+
+            <node-view-title v-else :node="activeNode.data" block />
           </dot-button>
         </foreignObject>
       </g>
     </map-zoom>
+
+    <node-preview-zone v-model="previewNode" :nodes="dataNodes" @open-node="onPreviewNodeClick" />
   </b-overlay>
 </template>
 
@@ -52,26 +56,33 @@ import { mapGetters } from 'vuex'
 import { line } from 'd3-shape'
 import { forceSimulation, forceLink, forceManyBody, forceX, forceY } from 'd3-force'
 
-import { trim, toCommaList } from '@/helpers/common'
-import { MapZoom } from '@/components/layouts'
+import { MapZoom, NodePreviewZone } from '@/components/layouts'
+import { NodeViewTitle } from '@/components/nodes'
 
 
 export default {
   name: 'LibraryTree',
 
   components: {
-    MapZoom
+    MapZoom,
+    NodePreviewZone,
+    NodeViewTitle
   },
 
   data () {
     return {
-      activeNode: null
+      activeNode: null,
+      previewNode: null
     }
   },
 
   computed: {
     ...mapGetters(['nodeTree']),
 
+    dataNodes () {
+      return this.nodeTree.nodes.map(node => node.data)
+    },
+
     // ONE TIME GETTER
     simulation () {
       return forceSimulation()
@@ -98,6 +109,7 @@ export default {
   watch: {
     nodeTree (tree) {
       this.activeNode = null
+      this.previewNode = null
       this.simulation.nodes(tree.nodes)
       this.simulation.force('link').links(tree.links)
       this.simulation.alpha(0.5).restart()
@@ -105,15 +117,16 @@ export default {
   },
 
   methods: {
-    toCommaList,
-    trim,
-
     onNodeClick (node) {
-      if (node.parents && node.parents.length) {
-        this.$emit('open-node', { parentId: node.parents[0].id, childId: node.id })
-      } else {
-        this.$emit('open-node', { parentId: node.id })
-      }
+      this.$store.dispatch('GET_NODE', { id: node.id, dataLevel: 'partial' })
+      this.previewNode = node
+      this.$root.$emit('bv::show::popover', 'preview-node-' + node.id)
+    },
+
+    onPreviewNodeClick (ids) {
+      this.$root.$emit('bv::hide::popover', 'preview-node-' + this.previewNode.id)
+      this.$emit('open-node', ids)
+      this.previewNode = null
     }
   },
 
@@ -140,6 +153,7 @@ export default {
   }
 
   &-dot {
+    cursor: pointer;
     r: 9.5px;
 
     @each $color, $value in $theme-colors {
@@ -177,5 +191,10 @@ foreignObject {
 
 .dot-btn {
   transform: translate(-50%, -50%);
+  pointer-events: none;
+
+  h6 {
+    margin: 0;
+  }
 }
 </style>