|  | @@ -0,0 +1,162 @@
 | 
	
		
			
				|  |  | +<template>
 | 
	
		
			
				|  |  | +  <article
 | 
	
		
			
				|  |  | +    class="node-view"
 | 
	
		
			
				|  |  | +    :class="['node-view-' + mode, 'node-view-' + type, 'node-view-' + nodeVariant]"
 | 
	
		
			
				|  |  | +  >
 | 
	
		
			
				|  |  | +    <div v-if="!loading" class="node-view-wrapper">
 | 
	
		
			
				|  |  | +      <component
 | 
	
		
			
				|  |  | +        :is="'node-view-header-' + type"
 | 
	
		
			
				|  |  | +        v-bind="{ node, mode }"
 | 
	
		
			
				|  |  | +        class="node-view-header"
 | 
	
		
			
				|  |  | +      />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      <node-view-body v-bind="{ content: node.content, type: nodeType, mode }" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      <node-view-footer
 | 
	
		
			
				|  |  | +        v-bind="{ node, mode, type: nodeType }"
 | 
	
		
			
				|  |  | +        class="node-view-footer"
 | 
	
		
			
				|  |  | +      />
 | 
	
		
			
				|  |  | +    </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    <b-overlay
 | 
	
		
			
				|  |  | +      :show="loading"
 | 
	
		
			
				|  |  | +      :spinner-variant="nodeVariant === 'depart' ? 'dark' : 'light'"
 | 
	
		
			
				|  |  | +      no-wrap
 | 
	
		
			
				|  |  | +    />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    <slot name="bottom" />
 | 
	
		
			
				|  |  | +  </article>
 | 
	
		
			
				|  |  | +</template>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<script>
 | 
	
		
			
				|  |  | +import {
 | 
	
		
			
				|  |  | +  NodeViewHeaderRef,
 | 
	
		
			
				|  |  | +  NodeViewHeaderProd,
 | 
	
		
			
				|  |  | +  NodeViewBody,
 | 
	
		
			
				|  |  | +  NodeViewFooter
 | 
	
		
			
				|  |  | +} from '@/components/nodes'
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +export default {
 | 
	
		
			
				|  |  | +  name: 'NodeView',
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  components: {
 | 
	
		
			
				|  |  | +    NodeViewHeaderRef,
 | 
	
		
			
				|  |  | +    NodeViewHeaderProd,
 | 
	
		
			
				|  |  | +    NodeViewFooter,
 | 
	
		
			
				|  |  | +    NodeViewBody
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  props: {
 | 
	
		
			
				|  |  | +    node: { type: Object, default: undefined },
 | 
	
		
			
				|  |  | +    variant: { type: String, default: 'dark' },
 | 
	
		
			
				|  |  | +    type: { type: String, default: 'ref' },
 | 
	
		
			
				|  |  | +    mode: { type: String, default: 'view' }
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  computed: {
 | 
	
		
			
				|  |  | +    loading () {
 | 
	
		
			
				|  |  | +      const dataLevel = this.mode === 'view' ? 2 : 1
 | 
	
		
			
				|  |  | +      return this.node === undefined || this.node.dataLevel < dataLevel
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    nodeVariant () {
 | 
	
		
			
				|  |  | +      return this.node !== undefined ? this.node.variant : this.variant
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    nodeType () {
 | 
	
		
			
				|  |  | +      return this.node !== undefined ? this.node.type : this.type
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +</script>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<style lang="scss" scoped>
 | 
	
		
			
				|  |  | +.node-view {
 | 
	
		
			
				|  |  | +  position: relative;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  &-wrapper {
 | 
	
		
			
				|  |  | +    display: flex;
 | 
	
		
			
				|  |  | +    flex-direction: column;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // ╭─╴╭─┐┌─╮┌─╮
 | 
	
		
			
				|  |  | +  // │  ├─┤├┬╯│ │
 | 
	
		
			
				|  |  | +  // ╰─╴╵ ╵╵ ╰└─╯
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  &-card {
 | 
	
		
			
				|  |  | +    width: 560px;
 | 
	
		
			
				|  |  | +    height: 330px;
 | 
	
		
			
				|  |  | +    max-width: 560px;
 | 
	
		
			
				|  |  | +    max-height: 330px;
 | 
	
		
			
				|  |  | +    box-shadow: .5rem .5rem 1rem rgba($black, .25);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  &-card &-header {
 | 
	
		
			
				|  |  | +    padding: $node-card-spacer-sm-y $node-card-spacer-sm-x 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @include media-breakpoint-up(md) {
 | 
	
		
			
				|  |  | +      padding: $node-card-spacer-y $node-card-spacer-x 0;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  &-card &-footer {
 | 
	
		
			
				|  |  | +    padding: $node-card-spacer-y $node-card-spacer-x $node-card-spacer-y * 2;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @include media-breakpoint-up(md) {
 | 
	
		
			
				|  |  | +      padding: $node-card-spacer-sm-y $node-card-spacer-sm-x $node-card-spacer-sm-y * 2;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // ╷ ╷╶┬╴┌─╴╷╷╷
 | 
	
		
			
				|  |  | +  // │╭╯ │ ├─╴│││
 | 
	
		
			
				|  |  | +  // ╰╯ ╶┴╴╰─╴╰╯╯
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  &-view {
 | 
	
		
			
				|  |  | +    width: 100%;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @include media-breakpoint-up(md) {
 | 
	
		
			
				|  |  | +      height: 100%;
 | 
	
		
			
				|  |  | +      overflow-y: auto;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      .node-view-wrapper {
 | 
	
		
			
				|  |  | +        min-height: 100%;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  &-view &-header {
 | 
	
		
			
				|  |  | +    padding: $node-view-spacer-sm-y $node-view-spacer-sm-x 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @include media-breakpoint-up(md) {
 | 
	
		
			
				|  |  | +      padding: $node-view-spacer-y $node-view-spacer-x 0;
 | 
	
		
			
				|  |  | +      position: sticky;
 | 
	
		
			
				|  |  | +      z-index: 1;
 | 
	
		
			
				|  |  | +      top: 0;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  &-view &-footer {
 | 
	
		
			
				|  |  | +    padding: $node-view-spacer-sm-y $node-view-spacer-sm-x;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @include media-breakpoint-up(md) {
 | 
	
		
			
				|  |  | +      padding: $node-view-spacer-y $node-view-spacer-x;
 | 
	
		
			
				|  |  | +      position: sticky;
 | 
	
		
			
				|  |  | +      bottom: 0;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  @each $color, $value in $theme-colors {
 | 
	
		
			
				|  |  | +    &-#{$color} {
 | 
	
		
			
				|  |  | +      background-color: lighten($value, 3.25%);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      .node-view-header,
 | 
	
		
			
				|  |  | +      .node-view-footer {
 | 
	
		
			
				|  |  | +        background-color: lighten($value, 3.25%);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +</style>
 |