瀏覽代碼

improve NodeBook layout

axolotle 2 年之前
父節點
當前提交
fab868c7ed

+ 72 - 82
src/components/layouts/NodeBook.vue

@@ -3,14 +3,14 @@
     class="node-book"
   >
     <section
-      class="node-book-stack no-events-container"
+      class="node-book-stack"
       :style="`--count: ${nodes.length - 1}; --h: ${stackHeight}px;`"
     >
       <div
         v-for="({ parent, children }, i) in nodes" :key="parent.id"
         class="node-book-stack-item node-book-stack-item-parent splitted no-events-container"
         :class="{ active: i === nodes.length - 1 }"
-        :style="`--nth: ${i}`"
+        :style="`--nth: ${i};`"
       >
         <node-view-child-list
           v-if="parent.children && parent.children.length"
@@ -20,6 +20,7 @@
         />
 
         <node-view
+          :ref="'parent-' + parent.id"
           :node="parent"
           type="ref"
           mode="view"
@@ -36,10 +37,11 @@
           <div
             v-for="(child, j) in children" :key="child.id + '-cont'"
             class="node-book-stack-item"
-            :class="{ active: j === children.length - 1 }"
+            :class="{ active: j === children.length - 1 && i === nodes.length - 1 }"
             :style="`--nth: ${j}`"
           >
             <node-view
+              :ref="'child-' + child.id"
               :key="child.id"
               :node="child"
               mode="view"
@@ -84,15 +86,24 @@ export default {
 
     onNodeViewClick (e, parentIndex, childIndex) {
       if (e.target.classList.contains('btn') || window.innerWidth < 1024) return
+      const lastChildIndex = this.nodes[parentIndex].children.length - 1
       const parentIsLast = parentIndex === this.nodes.length - 1
       const childIsLast = childIndex !== undefined
-        ? childIndex === this.nodes[parentIndex].children.length - 1
+        ? childIndex === lastChildIndex
         : true
       if (parentIsLast && childIsLast) return
       const ids = { parentId: this.nodes[parentIndex].parent.id }
+      if (!parentIsLast) {
+        this.$refs['parent-' + ids.parentId][0].onScroll({}, true)
+      }
       if (childIndex !== undefined) {
         ids.childId = this.nodes[parentIndex].children[childIndex].id
       }
+      if (childIndex !== undefined || lastChildIndex > -1) {
+        const childId = childIndex !== undefined ? ids.childId : this.nodes[parentIndex].children[lastChildIndex].id
+        console.log(childId)
+        this.$refs['child-' + childId][0].onScroll({}, true)
+      }
       this.$emit('select-node', ids)
     }
   },
@@ -110,9 +121,7 @@ export default {
 .node-book {
   min-height: 100%;
 
-  @include media-breakpoint-down($layout-bp-down) {
-    background-color: $white;
-  }
+  background-color: rgba($white, .5);
 
   @include media-breakpoint-up($layout-bp) {
     height: 100%;
@@ -135,98 +144,79 @@ export default {
         top: calc(var(--h) * var(--nth));
         height: calc(100% - (var(--h) * var(--nth)));
 
-        &-parent > .node-view {
-          border-right: $line;
-        }
-
-        &-parent > .node-view {
+        ::v-deep > .node-view {
           border-top: $line;
         }
 
-        &:not(.node-book-stack-item-parent):first-child {
-          border-top: $line;
+        &-parent > .node-view {
+          border-right: $line;
         }
 
+        &:not(.active) {
+          ::v-deep > .node-view {
+            cursor: pointer;
+            overflow-y: hidden;
 
-        // BLURS
-        &-parent:not(.active) {
-          &::before,
-          &::after {
-            content: '';
-            pointer-events: none;
-            position: absolute;
-            z-index: 1;
-            display: block;
-            top: $border-width;
-            height: calc(var(--h) - #{$border-width});
-            background-color: rgba($white, .5);
-          }
-          &::before {
-            width: calc(50% - #{$border-width});
-            left: 0;
-          }
-          &::after {
-            width: 50%;
-            left: 50%;
-          }
-        }
+            &:not(:hover) {
+              .node-view-header-wrapper {
+                opacity: .5;
+              }
+            }
+            .node-view-body-wrapper,
+            .node-view-footer-wrapper {
+              opacity: .5;
+              pointer-events: none;
+            }
 
-        &-parent.active {
-          background-color: rgba($white, .5);
-        }
+            .node-view-header {
+              z-index: 0;
+              padding-top: $node-view-spacer-y * .75;
+              padding-bottom: $node-view-spacer-y * .75;
+            }
 
-        &:not(.active) {
-          .node-view {
-            cursor: pointer;
-          }
+            .node-view-header-ref {
+              h4 {
+                font-size: 1.2rem;
+              }
 
-          ::v-deep {
-            .node-view {
-              // overflow-y: hidden;
+              .edition {
+                font-size: 0.8rem;
+                display: none;
+              }
 
-              &-header {
-                z-index: 0;
+              .btn-url {
+                width: 20px;
+                height: 20px;
               }
             }
 
             .node-view-child-list {
               display: none;
             }
+
+            @each $color, $value in $theme-colors {
+              &-#{$color} {
+                background-color: lighten($value, 15%);
+
+                .node-view-header,
+                .node-view-footer {
+                  background-color: lighten($value, 15%);
+                }
+              }
+            }
+
+            &:hover {
+              .node-view-header {
+                z-index: 100;
+                border-bottom: $line !important;
+                padding-bottom: calc(#{$node-view-spacer-y * .75} - 2px);
+
+                h4 {
+                  margin-bottom: 0;
+                }
+              }
+            }
           }
-          // ::v-deep .node-view:not(:hover) {
-          //     .node-view-header {
-          //       padding-top: $node-view-spacer-sm-y;
-          //       padding-bottom: $node-view-spacer-sm-y;
-          //     }
-          //
-          //     h4 {
-          //       font-size: 2rem;
-          //       > * {
-          //         display: inline !important;
-          //       }
-          //       .edition {
-          //         display: none !important;
-          //       }
-          //       display: block;
-          //       display: -webkit-box;
-          //       -webkit-line-clamp: 1;
-          //       -webkit-box-orient: vertical;
-          //       text-overflow: ellipsis;
-          //       overflow: hidden;
-          //       max-height: 1.5em;
-          //     }
-          //
-          //     .node-view-header-prod h4 {
-          //       font-size: 1rem;
-          //     }
-          // }
-          //
-          // &:hover {
-          //   ::v-deep .node-view:hover .node-view-header {
-          //     z-index: calc(var(--count) + 10);
-          //     border-bottom: $line;
-          //   }
-          // }
         }
 
         &.splitted {

+ 42 - 13
src/components/nodes/NodeView.vue

@@ -2,16 +2,18 @@
   <article
     class="node-view"
     :class="['node-view-' + mode, 'node-view-' + type, 'node-view-' + nodeVariant, { 'preview': preview }]"
+    :style="`--scroll-top: ${scrollValue}px; --h-height: ${h}px;`"
   >
     <div v-if="!loading" class="node-view-wrapper" :id="`node-${mode}-${node.id}`">
       <component
+        ref="header"
         :is="'node-view-header-' + nodeType"
         v-bind="{ node, mode, showOrigin }"
         class="node-view-header"
-        :class="{ scrolling }"
+        :class="{ scrolling: scrollValue }"
       />
 
-      <node-view-body v-bind="{ node, type: nodeType, mode }" :class="{ scrolling }"/>
+      <node-view-body v-bind="{ node, type: nodeType, mode }" :class="{ scrolling: scrollValue }"/>
 
       <node-view-footer
         v-bind="{ node, mode, type: nodeType, preview, showOrigin }"
@@ -66,7 +68,7 @@ export default {
 
   data () {
     return {
-      scrolling: false
+      scrollValue: 0
     }
   },
 
@@ -87,13 +89,25 @@ export default {
   },
 
   methods: {
-    onScroll ({ target }) {
-      const prev = this.scrolling
-      this.scrolling = target.scrollTop !== 0
-      if (this.scrolling && !prev) {
-        this.$el.scrollTo(0, 1)
+    onScroll ({ target = this.$el }, fix = false) {
+      const prev = this.scrollValue
+      this.scrollValue = target.scrollTop
+
+      if (this.scrollValue && !prev) {
+        const h = this.$refs.header.$el.getBoundingClientRect().height
+        this.$nextTick(() => {
+          this.h = h - this.$refs.header.$el.getBoundingClientRect().height
+        })
       }
-    }
+
+      if (fix) {
+        setTimeout(() => {
+          if (this.scrollValue > 0 && target.scrollTop === 0) {
+            target.scrollTop = this.scrollValue
+          }
+        }, 50)
+      }
+    },
   },
 
   mounted () {
@@ -180,7 +194,11 @@ export default {
     padding: $node-view-spacer-sm-y $node-view-spacer-sm-x 0;
 
     @include media-breakpoint-up($size-bp) {
-      padding: $node-view-spacer-y $node-view-spacer-x 0;
+      padding: $node-view-spacer-y $node-view-spacer-x $node-view-spacer-y * .75;
+
+      h4 {
+        margin-bottom: 0;
+      }
     }
 
     @include media-breakpoint-up($layout-bp) {
@@ -189,21 +207,32 @@ export default {
       z-index: 1;
 
       &-ref.scrolling {
-
         h4 {
           font-size: 1.2rem;
         }
+
         .edition {
           font-size: 0.8rem;
         }
+
+        .btn-url {
+          width: 20px;
+          height: 20px;
+        }
       }
     }
   }
 
   &-view &-body {
     @include media-breakpoint-up($layout-bp) {
-      &-ref.scrolling {
-        padding-top: 4rem;
+      max-height: 100%;
+
+      &.scrolling {
+        clip-path: inset(var(--scroll-top) 0px 0px 0px);
+
+        &.node-view-body-ref {
+          padding-top: var(--h-height);
+        }
       }
     }
   }

+ 3 - 14
src/components/nodes/NodeViewHeaderProd.vue

@@ -13,7 +13,7 @@
         </div>
       </h4>
 
-      <button-close v-if="mode === 'view'" @click="onClose()" :style="`--offset: ${offset}px;`" />
+      <button-close v-if="mode === 'view'" @click="onClose()" />
     </div>
   </div>
 </template>
@@ -47,12 +47,6 @@ export default {
     }
   },
 
-  data () {
-    return {
-      offset: 0
-    }
-  },
-
   methods: {
     trim,
     toCommaList,
@@ -60,12 +54,6 @@ export default {
     onClose () {
       this.$parent.$emit('close-node', this.node.id)
     }
-  },
-
-  mounted () {
-    const parentContH = this.$el.parentElement.offsetWidth
-    const parentH = this.$el.parentElement.parentElement.offsetWidth
-    this.offset = (parentH - parentContH) * -1
   }
 }
 </script>
@@ -115,8 +103,9 @@ export default {
     position: relative;
     display: flex;
     float: right;
+
     @include media-breakpoint-up($layout-bp) {
-      right: var(--offset);
+      right: -13px;
     }
   }
 }

+ 2 - 14
src/components/nodes/NodeViewHeaderRef.vue

@@ -3,7 +3,7 @@
     class="node-view-header-ref" :class="'node-view-header-' + mode"
   >
     <div class="node-view-header-wrapper w-100">
-      <div class="nav-container" :style="`--offset: ${offset}px;`">
+      <div class="nav-container">
         <node-view-child-list
           v-if="mode === 'view' && node.children && node.children.length"
           :children="node.children"
@@ -39,12 +39,6 @@ export default {
     mode: { type: String, required: true }
   },
 
-  data () {
-    return {
-      offset: 0
-    }
-  },
-
   methods: {
     trim,
     toCommaList,
@@ -52,12 +46,6 @@ export default {
     onClose () {
       this.$parent.$emit('close-node', this.node.id)
     }
-  },
-
-  mounted () {
-    const parentContH = this.$el.parentElement.offsetWidth
-    const parentH = this.$el.parentElement.parentElement.offsetWidth
-    this.offset = (parentH - parentContH) * -1
   }
 }
 </script>
@@ -73,7 +61,7 @@ export default {
       display: flex;
       float: right;
       @include media-breakpoint-up($layout-bp) {
-        right: var(--offset);
+        right: -13px;
       }
   }