Files
DiceCloud/app/imports/client/ui/components/tree/TreeNode.vue
2023-10-03 16:28:20 +02:00

224 lines
5.2 KiB
Vue

<template lang="html">
<v-sheet
class="tree-node"
:class="{
'empty': !hasChildren,
'found': node._matchedDocumentFilter,
}"
:data-id="`tree-node-${node._id}`"
>
<div
class="layout align-center justify-start tree-node-title"
style="cursor: pointer;"
:class="selected && 'primary--text'"
@click.stop="$emit('selected', node._id)"
>
<v-btn
v-if="!startExpanded"
small
icon
:class="showExpanded ? 'rotate-90' : null"
:disabled="!hasChildren && !organize || !canExpand"
@click.stop="expanded = !expanded"
>
<v-icon v-if="canExpand && (hasChildren || organize)">
mdi-chevron-right
</v-icon>
</v-btn>
<div
class="layout align-center justify-start pr-1"
:class="{'ml-4': startExpanded}"
style="flex-grow: 0;"
>
<drag-handle
v-if="organize"
class="mr-2"
:class="selected && 'primary--text'"
:disabled="expanded"
/>
<!--{{node && node.order}}-->
<tree-node-view
:model="node"
:selected="selected"
:show-external-details="showExternalDetails"
/>
</div>
</div>
<v-expand-transition>
<div
v-show="showExpanded"
class="pl-3"
>
<v-fade-transition hide-on-leave>
<tree-node-list
v-if="showExpanded"
:node="node"
:children="computedChildren"
:group="group"
:organize="organize"
:selected-node="selectedNode"
:start-expanded="startExpanded"
:show-external-details="showExternalDetails"
@reordered="e => $emit('reordered', e)"
@reorganized="e => $emit('reorganized', e)"
@selected="e => $emit('selected', e)"
/>
<div v-else>
<div
v-for="i in children.length"
:key="i"
class="dummy-node"
/>
</div>
</v-fade-transition>
</div>
</v-expand-transition>
</v-sheet>
</template>
<script lang="js">
/**
* TreeNode's are list item views of character properties. Every property which
* can belong to the character is shown in the tree view of the character
* the tree view shows off the full character structure, and where each part of
* character comes from.
**/
import { canBeParent } from '/imports/api/parenting/parentingFunctions';
import { getPropertyIcon } from '/imports/constants/PROPERTIES';
import TreeNodeView from '/imports/client/ui/properties/treeNodeViews/TreeNodeView.vue';
import { isAncestor } from '/imports/api/parenting/parentingFunctions';
import { some } from 'lodash';
export default {
name: 'TreeNode',
components: {
TreeNodeView,
},
props: {
node: {
type: Object,
required: true,
},
group: {
type: String,
default: undefined,
},
organize: Boolean,
children: {
type: Array,
default: () => [],
},
getChildren: {
type: Function,
default: undefined,
},
selectedNode: {
type: Object,
default: undefined,
},
selected: Boolean,
startExpanded: Boolean,
showExternalDetails: Boolean,
},
data() {
return {
expanded: this.startExpanded ||
this.node._ancestorOfMatchedDocument ||
isAncestor(this.node, this.selectedNode),
}
},
computed: {
hasChildren() {
return this.children && !!this.children.length || this.lazy && !this.expanded;
},
showExpanded() {
return this.expanded && (this.organize || this.hasChildren)
},
computedChildren() {
let children = [];
if (this.children) {
children.push(...this.children)
}
if (this.getChildren) {
children.push(...this.getChildren())
}
return children;
},
canExpand() {
return canBeParent(this.node.type);
},
},
watch: {
'node._ancestorOfMatchedDocument'(value) {
this.expanded = !!value ||
some(this.selectedNode?.ancestors, ref => ref.id === this.node._id);
},
'selectedNode.parentId'() {
this.expanded = isAncestor(this.node, this.selectedNode) || this.expanded;
},
},
beforeCreate() {
this.$options.components.TreeNodeList = require('./TreeNodeList.vue').default
},
methods: {
icon(type) {
return getPropertyIcon(type);
},
}
};
</script>
<style lang="css" scoped>
.rotate-90 {
transform: rotate(90deg) translateZ(0);
}
.drag-area {
box-shadow: -2px 0px 0px 0px #808080;
margin-left: 0;
min-height: 32px;
}
.empty .drag-area {
box-shadow: -2px 0px 0px 0px rgb(128, 128, 128, 0.4);
}
.empty .v-btn {
opacity: 0.4;
}
.found {
background: rgba(200, 0, 0, 0.1) !important;
}
.ghost {
opacity: 0.5;
background: rgba(251, 0, 0, 0.3);
}
.v-icon.v-icon--disabled {
opacity: 0;
}
.v-icon {
transition: none !important;
}
.theme--light .tree-node-title:hover {
background-color: rgba(0, 0, 0, .04);
}
.theme--dark .tree-node-title:hover {
background-color: rgba(255, 255, 255, .04);
}
.tree-node-title {
transition: background ease 0.3s, color ease 0.15s;
}
.tree-node-title,
.dummy-node {
min-height: 40px;
}
</style>