Files
enfrancais-app/src/components/nodes/NodeView.vue
T

189 lines
4.0 KiB
Vue

<template>
<article
class="node-view"
:class="['node-view-' + mode, 'node-view-' + type, 'node-view-' + nodeVariant, { 'preview': preview }]"
>
<div v-if="!loading" class="node-view-wrapper" :id="`node-${mode}-${node.id}`">
<component
:is="'node-view-header-' + nodeType"
v-bind="{ node, mode }"
class="node-view-header"
/>
<node-view-body v-bind="{ content: node.content, nodeId: node.id, notes: node.notes, type: nodeType, mode }" />
<node-view-footer
v-bind="{ node, mode, type: nodeType, preview }"
class="node-view-footer"
/>
</div>
<node-view-child-list-group
v-if="!loading && preview && node.children && node.children.length"
:children="node.children"
/>
<b-overlay
:show="loading"
:spinner-variant="nodeVariant === 'depart' ? 'dark' : 'light'"
no-wrap
/>
</article>
</template>
<script>
import {
NodeViewChildListGroup,
NodeViewHeaderRef,
NodeViewHeaderProd,
NodeViewBody,
NodeViewFooter
} from '@/components/nodes'
export default {
name: 'NodeView',
components: {
NodeViewChildListGroup,
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' },
preview: { type: Boolean, default: false }
},
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">
.node-view {
position: relative;
&-wrapper {
display: flex;
flex-direction: column;
}
// ╭─╴╭─┐┌─╮┌─╮
// │ ├─┤├┬╯│ │
// ╰─╴╵ ╵╵ ╰└─╯
&-card {
width: 100%;
.node-view-wrapper {
pointer-events: none;
width: 100%;
height: 100%;
overflow: hidden;
}
&.node-view-depart {
box-shadow: .5rem .5rem 1rem rgba($black, .25);
.node-view-child-list-group {
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($size-bp) {
padding: $node-card-spacer-y $node-card-spacer-x 0;
}
}
&-card &-footer {
padding: $node-card-spacer-sm-y $node-card-spacer-sm-x $node-card-spacer-sm-y * 2;
position: sticky;
bottom: 0;
@include media-breakpoint-up($size-bp) {
padding: $node-card-spacer-y $node-card-spacer-x $node-card-spacer-y * 2;
}
}
// ╷ ╷╶┬╴┌─╴╷╷╷
// │╭╯ │ ├─╴│││
// ╰╯ ╶┴╴╰─╴╰╯╯
&-view {
width: 100%;
@include media-breakpoint-up($layout-bp) {
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($size-bp) {
padding: $node-view-spacer-y $node-view-spacer-x 0;
}
@include media-breakpoint-up($layout-bp) {
position: sticky;
top: 0;
z-index: 1;
}
}
&-view &-footer {
padding: $node-view-spacer-sm-y $node-view-spacer-sm-x;
@include media-breakpoint-up($size-bp) {
padding: $node-view-spacer-y $node-view-spacer-x;
}
@include media-breakpoint-up($layout-bp) {
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>