Made tree tab work on mobile. prevented overflow of long titles
This commit is contained in:
@@ -1,61 +1,69 @@
|
||||
<template lang="html">
|
||||
<v-sheet
|
||||
class="tree-node"
|
||||
:class="!hasChildren ? 'empty' : null"
|
||||
:data-id="`tree-node-${node._id}`"
|
||||
>
|
||||
<div
|
||||
class="layout row align-center justify-start tree-node-title"
|
||||
style="cursor: pointer;"
|
||||
:class="selected && 'primary--text'"
|
||||
@click.stop="$emit('selected', node._id)"
|
||||
>
|
||||
<v-btn
|
||||
small icon
|
||||
:class="showExpanded ? 'rotate-90' : null"
|
||||
@click.stop="expanded = !expanded"
|
||||
:disabled="!hasChildren && !organize || !canExpand"
|
||||
>
|
||||
<v-icon v-if="canExpand && (hasChildren || organize)">chevron_right</v-icon>
|
||||
</v-btn>
|
||||
<div
|
||||
class="layout row align-center justify-start"
|
||||
style="flex-grow: 0;"
|
||||
>
|
||||
<v-icon
|
||||
class="handle mr-2"
|
||||
v-if="organize"
|
||||
:class="selected && 'primary--text'"
|
||||
:disabled="expanded"
|
||||
>drag_handle</v-icon>
|
||||
<property-icon
|
||||
v-if="node.type"
|
||||
class="mr-2"
|
||||
:type="node.type"
|
||||
:class="selected && 'primary--text'"
|
||||
/>
|
||||
<div class="text-no-wrap text-truncate">
|
||||
<!--{{node && node.order}}-->
|
||||
{{getTitle}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<v-expand-transition>
|
||||
<div v-if="showExpanded" class="pl-3">
|
||||
<tree-node-list
|
||||
v-if="showExpanded"
|
||||
:node="node"
|
||||
:children="computedChildren"
|
||||
:group="group"
|
||||
:organize="organize"
|
||||
:selected-node-id="selectedNodeId"
|
||||
@reordered="e => $emit('reordered', e)"
|
||||
@reorganized="e => $emit('reorganized', e)"
|
||||
@selected="e => $emit('selected', e)"
|
||||
/>
|
||||
</div>
|
||||
</v-expand-transition>
|
||||
</v-sheet>
|
||||
<v-sheet
|
||||
class="tree-node"
|
||||
:class="!hasChildren ? 'empty' : null"
|
||||
:data-id="`tree-node-${node._id}`"
|
||||
>
|
||||
<div
|
||||
class="layout row align-center justify-start tree-node-title"
|
||||
style="cursor: pointer;"
|
||||
:class="selected && 'primary--text'"
|
||||
@click.stop="$emit('selected', node._id)"
|
||||
>
|
||||
<v-btn
|
||||
small
|
||||
icon
|
||||
:class="showExpanded ? 'rotate-90' : null"
|
||||
:disabled="!hasChildren && !organize || !canExpand"
|
||||
@click.stop="expanded = !expanded"
|
||||
>
|
||||
<v-icon v-if="canExpand && (hasChildren || organize)">
|
||||
chevron_right
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
<div
|
||||
class="layout row align-center justify-start pr-1"
|
||||
style="flex-grow: 0;"
|
||||
>
|
||||
<v-icon
|
||||
v-if="organize"
|
||||
class="handle mr-2"
|
||||
:class="selected && 'primary--text'"
|
||||
:disabled="expanded"
|
||||
>
|
||||
drag_handle
|
||||
</v-icon>
|
||||
<property-icon
|
||||
v-if="node.type"
|
||||
class="mr-2"
|
||||
:type="node.type"
|
||||
:class="selected && 'primary--text'"
|
||||
/>
|
||||
<div class="text-no-wrap text-truncate">
|
||||
<!--{{node && node.order}}-->
|
||||
{{ getTitle }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<v-expand-transition>
|
||||
<div
|
||||
v-if="showExpanded"
|
||||
class="pl-3"
|
||||
>
|
||||
<tree-node-list
|
||||
v-if="showExpanded"
|
||||
:node="node"
|
||||
:children="computedChildren"
|
||||
:group="group"
|
||||
:organize="organize"
|
||||
:selected-node-id="selectedNodeId"
|
||||
@reordered="e => $emit('reordered', e)"
|
||||
@reorganized="e => $emit('reorganized', e)"
|
||||
@selected="e => $emit('selected', e)"
|
||||
/>
|
||||
</div>
|
||||
</v-expand-transition>
|
||||
</v-sheet>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -70,16 +78,10 @@
|
||||
import PROPERTIES from '/imports/constants/PROPERTIES.js'
|
||||
|
||||
export default {
|
||||
name: 'tree-node',
|
||||
beforeCreate() {
|
||||
this.$options.components.TreeNodeList = require('./TreeNodeList.vue').default
|
||||
},
|
||||
name: 'TreeNode',
|
||||
components: {
|
||||
PropertyIcon,
|
||||
},
|
||||
data(){ return {
|
||||
expanded: false,
|
||||
}},
|
||||
props: {
|
||||
node: Object,
|
||||
group: String,
|
||||
@@ -89,6 +91,9 @@
|
||||
selectedNodeId: String,
|
||||
selected: Boolean,
|
||||
},
|
||||
data(){ return {
|
||||
expanded: false,
|
||||
}},
|
||||
computed: {
|
||||
hasChildren(){
|
||||
return this.children && this.children.length || this.lazy && !this.expanded;
|
||||
@@ -117,6 +122,9 @@
|
||||
return prop && prop.name;
|
||||
}
|
||||
},
|
||||
beforeCreate() {
|
||||
this.$options.components.TreeNodeList = require('./TreeNodeList.vue').default
|
||||
},
|
||||
methods: {
|
||||
icon(type){
|
||||
return PROPERTY_ICONS[type];
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
<template lang="html">
|
||||
<div class="tree-tab">
|
||||
<div
|
||||
class="tree-tab pa-4"
|
||||
style="max-height: calc(100vh - 96px); display: flex;"
|
||||
>
|
||||
<v-card
|
||||
class="ma-4 layout row"
|
||||
class="layout row"
|
||||
style="max-height: 100%;"
|
||||
data-id="creature-tree-card"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="layout column"
|
||||
:style="
|
||||
$vuetify.breakpoint.mdAndUp &&
|
||||
'max-width: 400px; min-width: 320px;'
|
||||
"
|
||||
>
|
||||
<v-toolbar
|
||||
flat
|
||||
dense
|
||||
@@ -32,45 +42,47 @@
|
||||
deletable-chips
|
||||
/>
|
||||
<creature-properties-tree
|
||||
class="pt-0"
|
||||
class="pt-0 flex"
|
||||
style="overflow-y: auto;"
|
||||
:root="{collection: 'creatures', id: creatureId}"
|
||||
:organize="organize"
|
||||
:selected-node-id="selected"
|
||||
:filter="filter"
|
||||
style="min-width: 320px;"
|
||||
@selected="e => selected = e"
|
||||
@selected="clickNode"
|
||||
/>
|
||||
</div>
|
||||
<v-divider vertical />
|
||||
<div
|
||||
style="width: 100%; background-color: inherit;"
|
||||
data-id="selected-node-card"
|
||||
>
|
||||
<v-toolbar
|
||||
dense
|
||||
flat
|
||||
<template v-if="$vuetify.breakpoint.mdAndUp">
|
||||
<v-divider vertical />
|
||||
<div
|
||||
style="width: 100%; background-color: inherit;"
|
||||
data-id="selected-node-card"
|
||||
>
|
||||
<property-icon
|
||||
:type="selectedProperty && selectedProperty.type"
|
||||
class="mr-2"
|
||||
/>
|
||||
<div class="title">
|
||||
{{ getPropertyName(selectedProperty && selectedProperty.type) }}
|
||||
</div>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
v-if="selectedProperty"
|
||||
<v-toolbar
|
||||
dense
|
||||
flat
|
||||
icon
|
||||
@click="editCreatureProperty"
|
||||
>
|
||||
<v-icon>create</v-icon>
|
||||
</v-btn>
|
||||
</v-toolbar>
|
||||
<v-card-text>
|
||||
<property-viewer :model="selectedProperty" />
|
||||
</v-card-text>
|
||||
</div>
|
||||
<property-icon
|
||||
:type="selectedProperty && selectedProperty.type"
|
||||
class="mr-2"
|
||||
/>
|
||||
<div class="title">
|
||||
{{ getPropertyName(selectedProperty && selectedProperty.type) }}
|
||||
</div>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
v-if="selectedProperty"
|
||||
flat
|
||||
icon
|
||||
@click="editCreatureProperty"
|
||||
>
|
||||
<v-icon>create</v-icon>
|
||||
</v-btn>
|
||||
</v-toolbar>
|
||||
<v-card-text>
|
||||
<property-viewer :model="selectedProperty" />
|
||||
</v-card-text>
|
||||
</div>
|
||||
</template>
|
||||
</v-card>
|
||||
<v-speed-dial
|
||||
v-model="fab"
|
||||
@@ -107,138 +119,157 @@
|
||||
|
||||
<script>
|
||||
import CreaturePropertiesTree from '/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue';
|
||||
import CreatureProperties, {
|
||||
insertProperty,
|
||||
insertPropertyFromLibraryNode
|
||||
} from '/imports/api/creature/CreatureProperties.js';
|
||||
import PropertyViewer from '/imports/ui/properties/shared/PropertyViewer.vue';
|
||||
import { setDocToLastOrder } from '/imports/api/parenting/order.js';
|
||||
import PropertyIcon from '/imports/ui/properties/shared/PropertyIcon.vue';
|
||||
import { getPropertyName } from '/imports/constants/PROPERTIES.js';
|
||||
import CreatureProperties, {
|
||||
insertProperty,
|
||||
insertPropertyFromLibraryNode
|
||||
} from '/imports/api/creature/CreatureProperties.js';
|
||||
import PropertyViewer from '/imports/ui/properties/shared/PropertyViewer.vue';
|
||||
import { setDocToLastOrder } from '/imports/api/parenting/order.js';
|
||||
import PropertyIcon from '/imports/ui/properties/shared/PropertyIcon.vue';
|
||||
import { getPropertyName } from '/imports/constants/PROPERTIES.js';
|
||||
import LabeledFab from '/imports/ui/components/LabeledFab.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CreaturePropertiesTree,
|
||||
PropertyViewer,
|
||||
PropertyIcon,
|
||||
export default {
|
||||
components: {
|
||||
CreaturePropertiesTree,
|
||||
PropertyViewer,
|
||||
PropertyIcon,
|
||||
LabeledFab,
|
||||
},
|
||||
props: {
|
||||
creatureId: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
data(){ return {
|
||||
organize: false,
|
||||
organizeDisabled: false,
|
||||
selected: undefined,
|
||||
fab: false,
|
||||
filterString: '',
|
||||
filterOptions: [
|
||||
{text: 'Actions', value: 'action'},
|
||||
{text: 'Attacks', value: 'attack'},
|
||||
{text: 'Attributes', value: 'attribute'},
|
||||
{text: 'Buffs', value: 'buff'},
|
||||
{text: 'Class Levels', value: 'classLevel'},
|
||||
{text: 'Damage Multipliers', value: 'damageMultiplier'},
|
||||
{text: 'Effects', value: 'effect'},
|
||||
{text: 'Experiences', value: 'experience'},
|
||||
{text: 'Features', value: 'feature'},
|
||||
{text: 'Folders', value: 'folder'},
|
||||
{text: 'Notes', value: 'note'},
|
||||
{text: 'Proficiencies', value: 'proficiency'},
|
||||
{text: 'Rolls', value: 'roll'},
|
||||
{text: 'Saving Throws', value: 'savingThrow'},
|
||||
{text: 'Skills', value: 'skill'},
|
||||
{text: 'Spell Lists', value: 'spellList'},
|
||||
{text: 'Spells', value: 'spell'},
|
||||
{text: 'Containers', value: 'container'},
|
||||
{text: 'Items', value: 'item'},
|
||||
],
|
||||
};},
|
||||
computed: {
|
||||
filter(){
|
||||
if (!this.filterString.length) return;
|
||||
let typeFilters = [];
|
||||
let nameFilters = [];
|
||||
this.filterString.forEach(filter => {
|
||||
if (filter.value){
|
||||
typeFilters.push(filter.value);
|
||||
} else {
|
||||
// escape string
|
||||
let term = filter.replace( /[-/\\^$*+?.()|[\]{}]/g, '\\$&' );
|
||||
},
|
||||
props: {
|
||||
creatureId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data(){ return {
|
||||
organize: false,
|
||||
organizeDisabled: false,
|
||||
selected: undefined,
|
||||
fab: false,
|
||||
filterString: '',
|
||||
filterOptions: [
|
||||
{text: 'Actions', value: 'action'},
|
||||
{text: 'Attacks', value: 'attack'},
|
||||
{text: 'Attributes', value: 'attribute'},
|
||||
{text: 'Buffs', value: 'buff'},
|
||||
{text: 'Class Levels', value: 'classLevel'},
|
||||
{text: 'Damage Multipliers', value: 'damageMultiplier'},
|
||||
{text: 'Effects', value: 'effect'},
|
||||
{text: 'Experiences', value: 'experience'},
|
||||
{text: 'Features', value: 'feature'},
|
||||
{text: 'Folders', value: 'folder'},
|
||||
{text: 'Notes', value: 'note'},
|
||||
{text: 'Proficiencies', value: 'proficiency'},
|
||||
{text: 'Rolls', value: 'roll'},
|
||||
{text: 'Saving Throws', value: 'savingThrow'},
|
||||
{text: 'Skills', value: 'skill'},
|
||||
{text: 'Spell Lists', value: 'spellList'},
|
||||
{text: 'Spells', value: 'spell'},
|
||||
{text: 'Containers', value: 'container'},
|
||||
{text: 'Items', value: 'item'},
|
||||
],
|
||||
};},
|
||||
computed: {
|
||||
filter(){
|
||||
if (!this.filterString.length) return;
|
||||
let typeFilters = [];
|
||||
let nameFilters = [];
|
||||
this.filterString.forEach(filter => {
|
||||
if (filter.value){
|
||||
typeFilters.push(filter.value);
|
||||
} else {
|
||||
// escape string
|
||||
let term = filter.replace( /[-/\\^$*+?.()|[\]{}]/g, '\\$&' );
|
||||
var reg = new RegExp( '.*' + term + '.*', 'i' );
|
||||
nameFilters.push(reg)
|
||||
}
|
||||
});
|
||||
return {$or: [
|
||||
{type: {$in: typeFilters}},
|
||||
{name: {$in: nameFilters}},
|
||||
]};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
filter(filter){
|
||||
if (filter) {
|
||||
this.organize = false;
|
||||
this.organizeDisabled = true;
|
||||
} else {
|
||||
this.organizeDisabled = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
insertCreatureProperty(){
|
||||
let that = this;
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-creation-dialog',
|
||||
elementId: 'insert-creature-property-fab',
|
||||
callback(creatureProperty){
|
||||
if (!creatureProperty) return;
|
||||
creatureProperty.parent = {collection: 'creatures', id: that.creatureId};
|
||||
creatureProperty.ancestors = [ {collection: 'creatures', id: that.creatureId}];
|
||||
setDocToLastOrder({collection: CreatureProperties, doc: creatureProperty});
|
||||
let creaturePropertyId = insertProperty.call({creatureProperty});
|
||||
return creaturePropertyId;
|
||||
}
|
||||
});
|
||||
},
|
||||
propertyFromLibrary(){
|
||||
let that = this;
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-from-library-dialog',
|
||||
elementId: 'insert-creature-property-fab',
|
||||
callback(libraryNode){
|
||||
if (!libraryNode) return;
|
||||
insertPropertyFromLibraryNode.call({
|
||||
nodeId: libraryNode._id,
|
||||
parentRef: {collection: 'creatures', id: that.creatureId},
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
editCreatureProperty(){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: 'selected-node-card',
|
||||
data: {
|
||||
_id: this.selected,
|
||||
startInEditTab: true,
|
||||
},
|
||||
});
|
||||
},
|
||||
getPropertyName,
|
||||
},
|
||||
meteor: {
|
||||
selectedProperty(){
|
||||
return CreatureProperties.findOne({
|
||||
_id: this.selected,
|
||||
removed: {$ne: true}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
nameFilters.push(reg)
|
||||
}
|
||||
});
|
||||
return {$or: [
|
||||
{type: {$in: typeFilters}},
|
||||
{name: {$in: nameFilters}},
|
||||
]};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
filter(filter){
|
||||
if (filter) {
|
||||
this.organize = false;
|
||||
this.organizeDisabled = true;
|
||||
} else {
|
||||
this.organizeDisabled = false;
|
||||
}
|
||||
},
|
||||
'$vuetify.breakpoint.mdAndUp'(mdAndUp){
|
||||
if (!mdAndUp){
|
||||
this.selected = undefined;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clickNode(id){
|
||||
if (this.$vuetify.breakpoint.mdAndUp){
|
||||
this.selected = id;
|
||||
} else {
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `tree-node-${id}`,
|
||||
data: {
|
||||
_id: id,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
insertCreatureProperty(){
|
||||
let that = this;
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-creation-dialog',
|
||||
elementId: 'insert-creature-property-fab',
|
||||
callback(creatureProperty){
|
||||
if (!creatureProperty) return;
|
||||
creatureProperty.parent = {collection: 'creatures', id: that.creatureId};
|
||||
creatureProperty.ancestors = [ {collection: 'creatures', id: that.creatureId}];
|
||||
setDocToLastOrder({collection: CreatureProperties, doc: creatureProperty});
|
||||
let creaturePropertyId = insertProperty.call({creatureProperty});
|
||||
return creaturePropertyId;
|
||||
}
|
||||
});
|
||||
},
|
||||
propertyFromLibrary(){
|
||||
let that = this;
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-from-library-dialog',
|
||||
elementId: 'insert-creature-property-fab',
|
||||
callback(libraryNode){
|
||||
if (!libraryNode) return;
|
||||
insertPropertyFromLibraryNode.call({
|
||||
nodeId: libraryNode._id,
|
||||
parentRef: {collection: 'creatures', id: that.creatureId},
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
editCreatureProperty(){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: 'selected-node-card',
|
||||
data: {
|
||||
_id: this.selected,
|
||||
startInEditTab: true,
|
||||
},
|
||||
});
|
||||
},
|
||||
getPropertyName,
|
||||
},
|
||||
meteor: {
|
||||
selectedProperty(){
|
||||
return CreatureProperties.findOne({
|
||||
_id: this.selected,
|
||||
removed: {$ne: true}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
<template lang="html">
|
||||
<v-card-text style="width: initial; max-width: 100%;">
|
||||
<tree-node-list
|
||||
v-if="root"
|
||||
:children="children"
|
||||
:group="group"
|
||||
:organize="organize"
|
||||
:selected-node-id="selectedNodeId"
|
||||
@selected="e => $emit('selected', e)"
|
||||
@reordered="reordered"
|
||||
@reorganized="reorganized"
|
||||
/>
|
||||
</v-card-text>
|
||||
<tree-node-list
|
||||
v-if="root"
|
||||
:children="children"
|
||||
:group="group"
|
||||
:organize="organize"
|
||||
:selected-node-id="selectedNodeId"
|
||||
@selected="e => $emit('selected', e)"
|
||||
@reordered="reordered"
|
||||
@reorganized="reorganized"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
Reference in New Issue
Block a user