Compare commits
8 Commits
2.0-beta.3
...
2.0-beta.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f86152675f | ||
|
|
cbac5264cd | ||
|
|
34e3325464 | ||
|
|
79c9e67ce2 | ||
|
|
4c2aabf90d | ||
|
|
48331d3806 | ||
|
|
45f05d0d34 | ||
|
|
58629c92f4 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
build
|
||||||
@@ -11,8 +11,8 @@ import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js'
|
|||||||
export default function applyAction(node, actionContext) {
|
export default function applyAction(node, actionContext) {
|
||||||
applyNodeTriggers(node, 'before', actionContext);
|
applyNodeTriggers(node, 'before', actionContext);
|
||||||
const prop = node.node;
|
const prop = node.node;
|
||||||
let targets = actionContext.targets;
|
if (prop.target === 'self') actionContext.targets = [actionContext.creature];
|
||||||
if (prop.target === 'self') targets = [actionContext.creature];
|
const targets = actionContext.targets;
|
||||||
|
|
||||||
// Log the name and summary
|
// Log the name and summary
|
||||||
let content = { name: prop.name };
|
let content = { name: prop.name };
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ export default function computeToggleDependencies(node, dependencyGraph){
|
|||||||
prop.enabled
|
prop.enabled
|
||||||
) return;
|
) return;
|
||||||
walkDown(node.children, child => {
|
walkDown(node.children, child => {
|
||||||
child.node._computationDetails.toggleAncestors.push(prop);
|
// Only for children that aren't inactive
|
||||||
|
if (child.node.inactive) return;
|
||||||
// The child nodes depend on the toggle condition compuation
|
// The child nodes depend on the toggle condition compuation
|
||||||
|
child.node._computationDetails.toggleAncestors.push(prop);
|
||||||
dependencyGraph.addLink(child.node._id, prop._id, 'toggle');
|
dependencyGraph.addLink(child.node._id, prop._id, 'toggle');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,6 +89,10 @@ export function buildComputationFromProps(properties, creature, variables){
|
|||||||
// Walk the property trees computing things that need to be inherited
|
// Walk the property trees computing things that need to be inherited
|
||||||
walkDown(forest, node => {
|
walkDown(forest, node => {
|
||||||
computeInactiveStatus(node);
|
computeInactiveStatus(node);
|
||||||
|
});
|
||||||
|
// Inactive status must be complete for the whole tree before toggle deps
|
||||||
|
// are calculated
|
||||||
|
walkDown(forest, node => {
|
||||||
computeToggleDependencies(node, dependencyGraph);
|
computeToggleDependencies(node, dependencyGraph);
|
||||||
computeSlotQuantityFilled(node, dependencyGraph);
|
computeSlotQuantityFilled(node, dependencyGraph);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -51,11 +51,22 @@ function compute(computation, node){
|
|||||||
|
|
||||||
function pushDependenciesToStack(nodeId, graph, stack, computation){
|
function pushDependenciesToStack(nodeId, graph, stack, computation){
|
||||||
graph.forEachLinkedNode(nodeId, linkedNode => {
|
graph.forEachLinkedNode(nodeId, linkedNode => {
|
||||||
if (linkedNode._visitedChildren && !linkedNode._visited){
|
if (linkedNode._visitedChildren && !linkedNode._visited) {
|
||||||
const pather = path.nba(graph, {
|
// This is a dependency loop, find a path from the node to itself
|
||||||
oriented: true
|
// and store that path as a dependency loop error
|
||||||
});
|
const pather = path.nba(graph, { oriented: true });
|
||||||
const loop = pather.find(nodeId, nodeId);
|
let loop = [];
|
||||||
|
// Pather doesn't like going from a node to iteself, so find all the
|
||||||
|
// paths going from the next node back to the original node
|
||||||
|
// and return the shortest one
|
||||||
|
graph.forEachLinkedNode(nodeId, nextNode => {
|
||||||
|
const newLoop = pather.find(nextNode.id, nodeId);
|
||||||
|
if (!newLoop.length) return;
|
||||||
|
if (!loop.length || newLoop.length < loop.length - 1) {
|
||||||
|
loop = [linkedNode, ...newLoop];
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
if (loop.length) {
|
if (loop.length) {
|
||||||
computation.errors.push({
|
computation.errors.push({
|
||||||
type: 'dependencyLoop',
|
type: 'dependencyLoop',
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ export function getSingleProperty(creatureId, propertyId) {
|
|||||||
'removed': {$ne: true},
|
'removed': {$ne: true},
|
||||||
}, {
|
}, {
|
||||||
sort: { order: 1 },
|
sort: { order: 1 },
|
||||||
fields: { icon: 0 },
|
|
||||||
});
|
});
|
||||||
// console.timeEnd(`Cache miss on creature properties: ${creatureId}`);
|
// console.timeEnd(`Cache miss on creature properties: ${creatureId}`);
|
||||||
return prop;
|
return prop;
|
||||||
@@ -65,7 +64,6 @@ export function getProperties(creatureId) {
|
|||||||
'removed': {$ne: true},
|
'removed': {$ne: true},
|
||||||
}, {
|
}, {
|
||||||
sort: { order: 1 },
|
sort: { order: 1 },
|
||||||
fields: { icon: 0 },
|
|
||||||
}).fetch();
|
}).fetch();
|
||||||
// console.timeEnd(`Cache miss on creature properties: ${creatureId}`);
|
// console.timeEnd(`Cache miss on creature properties: ${creatureId}`);
|
||||||
return props;
|
return props;
|
||||||
@@ -90,7 +88,6 @@ export function getPropertiesOfType(creatureId, propType) {
|
|||||||
'type': propType,
|
'type': propType,
|
||||||
}, {
|
}, {
|
||||||
sort: { order: 1 },
|
sort: { order: 1 },
|
||||||
fields: { icon: 0 },
|
|
||||||
}).fetch();
|
}).fetch();
|
||||||
// console.timeEnd(`Cache miss on creature properties: ${creatureId}`);
|
// console.timeEnd(`Cache miss on creature properties: ${creatureId}`);
|
||||||
return props;
|
return props;
|
||||||
@@ -103,11 +100,7 @@ export function getCreature(creatureId) {
|
|||||||
if (creature) return creature;
|
if (creature) return creature;
|
||||||
}
|
}
|
||||||
// console.time(`Cache miss on Creature: ${creatureId}`);
|
// console.time(`Cache miss on Creature: ${creatureId}`);
|
||||||
const creature = Creatures.findOne(creatureId, {
|
const creature = Creatures.findOne(creatureId);
|
||||||
denormalizedStats: 1,
|
|
||||||
variables: 1,
|
|
||||||
dirty: 1,
|
|
||||||
});
|
|
||||||
// console.timeEnd(`Cache miss on Creature: ${creatureId}`);
|
// console.timeEnd(`Cache miss on Creature: ${creatureId}`);
|
||||||
return creature;
|
return creature;
|
||||||
}
|
}
|
||||||
@@ -149,6 +142,7 @@ export function getProperyAncestors(creatureId, propertyId) {
|
|||||||
// Fetch from database
|
// Fetch from database
|
||||||
return CreatureProperties.find({
|
return CreatureProperties.find({
|
||||||
_id: { $in: ancestorIds },
|
_id: { $in: ancestorIds },
|
||||||
|
removed: {$ne: true},
|
||||||
}, {
|
}, {
|
||||||
sort: { order: 1 },
|
sort: { order: 1 },
|
||||||
}).fetch();
|
}).fetch();
|
||||||
@@ -175,6 +169,8 @@ export function getPropertyDecendants(creatureId, propertyId) {
|
|||||||
return CreatureProperties.find({
|
return CreatureProperties.find({
|
||||||
'ancestors.id': propertyId,
|
'ancestors.id': propertyId,
|
||||||
removed: { $ne: true },
|
removed: { $ne: true },
|
||||||
|
}, {
|
||||||
|
sort: { order: 1 },
|
||||||
}).fetch();
|
}).fetch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,7 +195,6 @@ class LoadedCreature {
|
|||||||
removed: { $ne: true },
|
removed: { $ne: true },
|
||||||
}, {
|
}, {
|
||||||
sort: { order: 1 },
|
sort: { order: 1 },
|
||||||
fields: { icon: 0 },
|
|
||||||
}).observeChanges({
|
}).observeChanges({
|
||||||
added(id, fields) {
|
added(id, fields) {
|
||||||
fields._id = id;
|
fields._id = id;
|
||||||
|
|||||||
@@ -28,11 +28,11 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
<div
|
<div
|
||||||
class="layout align-center justify-start pr-1"
|
class="layout align-center justify-start pr-1"
|
||||||
style="flex-grow: 0;"
|
|
||||||
>
|
>
|
||||||
<!--{{node && node.order}}-->
|
<!--{{node && node.order}}-->
|
||||||
<div
|
<div
|
||||||
v-if="isSlot"
|
v-if="isSlot"
|
||||||
|
class="text-truncate"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
:class="{
|
:class="{
|
||||||
@@ -47,15 +47,38 @@
|
|||||||
:model="node"
|
:model="node"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<tree-node-view
|
<template
|
||||||
v-else
|
v-else
|
||||||
:model="node"
|
>
|
||||||
/>
|
<tree-node-view
|
||||||
|
:model="node"
|
||||||
|
/>
|
||||||
|
<v-spacer />
|
||||||
|
<v-btn
|
||||||
|
icon
|
||||||
|
:disabled="context.editPermission === false"
|
||||||
|
@click.stop="remove(node)"
|
||||||
|
>
|
||||||
|
<v-icon>
|
||||||
|
mdi-delete
|
||||||
|
</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
<template v-if="condenseChild">
|
<template v-if="condenseChild">
|
||||||
<span class="mr-4">:</span>
|
<span class="mr-4">:</span>
|
||||||
<tree-node-view
|
<tree-node-view
|
||||||
:model="children[0].node"
|
:model="children[0].node"
|
||||||
/>
|
/>
|
||||||
|
<v-spacer />
|
||||||
|
<v-btn
|
||||||
|
icon
|
||||||
|
:disabled="context.editPermission === false"
|
||||||
|
@click.stop="remove(children[0].node)"
|
||||||
|
>
|
||||||
|
<v-icon>
|
||||||
|
mdi-delete
|
||||||
|
</v-icon>
|
||||||
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -92,98 +115,118 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="js">
|
<script lang="js">
|
||||||
/**
|
/**
|
||||||
* TreeNode's are list item views of character properties. Every property which
|
* 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
|
* 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
|
* the tree view shows off the full character structure, and where each part of
|
||||||
* character comes from.
|
* character comes from.
|
||||||
**/
|
**/
|
||||||
import TreeNodeView from '/imports/ui/properties/treeNodeViews/TreeNodeView.vue';
|
import TreeNodeView from '/imports/ui/properties/treeNodeViews/TreeNodeView.vue';
|
||||||
import FillSlotButton from '/imports/ui/creature/buildTree/FillSlotButton.vue';
|
import FillSlotButton from '/imports/ui/creature/buildTree/FillSlotButton.vue';
|
||||||
import { some } from 'lodash';
|
import { some } from 'lodash';
|
||||||
|
import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
|
||||||
|
import softRemoveProperty from '/imports/api/creature/creatureProperties/methods/softRemoveProperty.js';
|
||||||
|
import restoreProperty from '/imports/api/creature/creatureProperties/methods/restoreProperty.js';
|
||||||
|
import getPropertyTitle from '/imports/ui/properties/shared/getPropertyTitle.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'BuildTreeNode',
|
name: 'BuildTreeNode',
|
||||||
components: {
|
components: {
|
||||||
TreeNodeView,
|
TreeNodeView,
|
||||||
FillSlotButton,
|
FillSlotButton,
|
||||||
|
},
|
||||||
|
inject: {
|
||||||
|
context: { default: {} }
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
node: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
},
|
},
|
||||||
props: {
|
children: {
|
||||||
node: {
|
type: Array,
|
||||||
type: Object,
|
default: () => [],
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
children: {
|
|
||||||
type: Array,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data(){return {
|
|
||||||
expanded: false,
|
|
||||||
/* expand if there's a slot needing attention:
|
|
||||||
this.node._descendantCanFill || (
|
|
||||||
this.node.type === 'propertySlot' &&
|
|
||||||
this. node.quantityExpected?.value === 0 ||
|
|
||||||
(this.node.quantityExpected?.value > 1 && this.node.spaceLeft > 0)
|
|
||||||
)
|
|
||||||
*/
|
|
||||||
}},
|
|
||||||
computed: {
|
|
||||||
condenseChild(){
|
|
||||||
return this.node.type === 'propertySlot' &&
|
|
||||||
this.children.length === 1 &&
|
|
||||||
this.children[0].node.type !== 'propertySlot' &&
|
|
||||||
this.node.quantityExpected &&
|
|
||||||
this.node.quantityExpected.value === 1;
|
|
||||||
},
|
|
||||||
isSlot(){
|
|
||||||
return this.node.type === 'propertySlot';
|
|
||||||
},
|
|
||||||
canFill(){
|
|
||||||
return !!this.node._canFill;
|
|
||||||
},
|
|
||||||
canFillWithOne(){
|
|
||||||
return this.isSlot &&
|
|
||||||
this.node.quantityExpected &&
|
|
||||||
this.node.quantityExpected.value === 1 &&
|
|
||||||
this.node.spaceLeft === 1
|
|
||||||
},
|
|
||||||
canFillWithMany(){
|
|
||||||
return this.isSlot && (
|
|
||||||
!this.node.quantityExpected ||
|
|
||||||
this.node.quantityExpected.value === 0 ||
|
|
||||||
(this.node.quantityExpected.value > 1 && this.node.spaceLeft > 0)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
hasChildren(){
|
|
||||||
return !!this.children && !!this.computedChildren.length || this.lazy && !this.expanded;
|
|
||||||
},
|
|
||||||
showExpanded(){
|
|
||||||
return this.canExpand && this.expanded;
|
|
||||||
},
|
|
||||||
computedChildren(){
|
|
||||||
if (this.condenseChild){
|
|
||||||
return this.children[0].children;
|
|
||||||
}
|
|
||||||
return this.children;
|
|
||||||
},
|
|
||||||
canExpand(){
|
|
||||||
return !!this.computedChildren.length || this.canFillWithMany;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
'node._ancestorOfMatchedDocument'(value){
|
|
||||||
this.expanded = !!value ||
|
|
||||||
some(this.selectedNode?.ancestors, ref => ref.id === this.node._id);
|
|
||||||
},
|
|
||||||
'selectedNode.ancestors'(value){
|
|
||||||
this.expanded = !!some(value, ref => ref.id === this.node._id) || this.expanded;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
beforeCreate() {
|
},
|
||||||
this.$options.components.BuildTreeNodeList = require('./BuildTreeNodeList.vue').default
|
data(){return {
|
||||||
},
|
expanded: false,
|
||||||
};
|
/* expand if there's a slot needing attention:
|
||||||
|
this.node._descendantCanFill || (
|
||||||
|
this.node.type === 'propertySlot' &&
|
||||||
|
this. node.quantityExpected?.value === 0 ||
|
||||||
|
(this.node.quantityExpected?.value > 1 && this.node.spaceLeft > 0)
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
}},
|
||||||
|
computed: {
|
||||||
|
condenseChild(){
|
||||||
|
return this.node.type === 'propertySlot' &&
|
||||||
|
this.children.length === 1 &&
|
||||||
|
this.children[0].node.type !== 'propertySlot' &&
|
||||||
|
this.node.quantityExpected &&
|
||||||
|
this.node.quantityExpected.value === 1;
|
||||||
|
},
|
||||||
|
isSlot(){
|
||||||
|
return this.node.type === 'propertySlot';
|
||||||
|
},
|
||||||
|
canFill(){
|
||||||
|
return !!this.node._canFill;
|
||||||
|
},
|
||||||
|
canFillWithOne(){
|
||||||
|
return this.isSlot &&
|
||||||
|
this.node.quantityExpected &&
|
||||||
|
this.node.quantityExpected.value === 1 &&
|
||||||
|
this.node.spaceLeft === 1
|
||||||
|
},
|
||||||
|
canFillWithMany(){
|
||||||
|
return this.isSlot && (
|
||||||
|
!this.node.quantityExpected ||
|
||||||
|
this.node.quantityExpected.value === 0 ||
|
||||||
|
(this.node.quantityExpected.value > 1 && this.node.spaceLeft > 0)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
hasChildren(){
|
||||||
|
return !!this.children && !!this.computedChildren.length || this.lazy && !this.expanded;
|
||||||
|
},
|
||||||
|
showExpanded(){
|
||||||
|
return this.canExpand && this.expanded;
|
||||||
|
},
|
||||||
|
computedChildren(){
|
||||||
|
if (this.condenseChild){
|
||||||
|
return this.children[0].children;
|
||||||
|
}
|
||||||
|
return this.children;
|
||||||
|
},
|
||||||
|
canExpand(){
|
||||||
|
return !!this.computedChildren.length || this.canFillWithMany;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'node._ancestorOfMatchedDocument'(value){
|
||||||
|
this.expanded = !!value ||
|
||||||
|
some(this.selectedNode?.ancestors, ref => ref.id === this.node._id);
|
||||||
|
},
|
||||||
|
'selectedNode.ancestors'(value){
|
||||||
|
this.expanded = !!some(value, ref => ref.id === this.node._id) || this.expanded;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
beforeCreate() {
|
||||||
|
this.$options.components.BuildTreeNodeList = require('./BuildTreeNodeList.vue').default
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
remove(model) {
|
||||||
|
const _id = model._id;
|
||||||
|
softRemoveProperty.call({_id});
|
||||||
|
snackbar({
|
||||||
|
text: `Deleted ${getPropertyTitle(model)}`,
|
||||||
|
callbackName: 'undo',
|
||||||
|
callback(){
|
||||||
|
restoreProperty.call({_id});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
v-model="fab"
|
v-model="fab"
|
||||||
color="primary"
|
color="primary"
|
||||||
fab
|
fab
|
||||||
|
small
|
||||||
data-id="insert-creature-property-fab"
|
data-id="insert-creature-property-fab"
|
||||||
class="insert-creature-property-fab"
|
class="insert-creature-property-fab"
|
||||||
small
|
|
||||||
>
|
>
|
||||||
<transition
|
<transition
|
||||||
name="fab-rotate"
|
name="fab-rotate"
|
||||||
@@ -48,12 +48,13 @@
|
|||||||
import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js';
|
import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js';
|
||||||
import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js';
|
import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js';
|
||||||
|
|
||||||
function getParentAndOrderFromSelectedTreeNode(creatureId){
|
function getParentAndOrderFromSelectedTreeNode(creatureId, $store){
|
||||||
// find the parent based on the currently selected property
|
// find the parent based on the currently selected property
|
||||||
let el = document.querySelector('.tree-tab .tree-node-title.primary--text');
|
let el = document.querySelector('.tree-tab .tree-node-title.primary--text');
|
||||||
let selectedComponent = el && el.parentElement.__vue__.$parent;
|
let selectedComponent = el && el.parentElement.__vue__.$parent;
|
||||||
let parentRef, order;
|
let parentRef, order;
|
||||||
if (selectedComponent){
|
const onTreeTab = $store.getters.tabNameById(creatureId) === 'tree';
|
||||||
|
if (onTreeTab && selectedComponent){
|
||||||
if (selectedComponent.showExpanded){
|
if (selectedComponent.showExpanded){
|
||||||
parentRef = {
|
parentRef = {
|
||||||
id: selectedComponent.node._id,
|
id: selectedComponent.node._id,
|
||||||
@@ -156,7 +157,7 @@
|
|||||||
let creatureId = this.creatureId;
|
let creatureId = this.creatureId;
|
||||||
let fab = hideFab();
|
let fab = hideFab();
|
||||||
|
|
||||||
let {parentRef, order } = getParentAndOrderFromSelectedTreeNode(creatureId);
|
let {parentRef, order } = getParentAndOrderFromSelectedTreeNode(creatureId, this.$store);
|
||||||
let parent;
|
let parent;
|
||||||
try {
|
try {
|
||||||
parent = fetchDocByRef(parentRef);
|
parent = fetchDocByRef(parentRef);
|
||||||
|
|||||||
@@ -14,17 +14,19 @@
|
|||||||
<v-fade-transition
|
<v-fade-transition
|
||||||
mode="out-in"
|
mode="out-in"
|
||||||
>
|
>
|
||||||
<v-app-bar-title :key="$store.state.pageTitle">
|
<v-toolbar-title :key="$store.state.pageTitle">
|
||||||
<div>
|
{{ $store.state.pageTitle }}
|
||||||
{{ $store.state.pageTitle }}
|
</v-toolbar-title>
|
||||||
</div>
|
|
||||||
</v-app-bar-title>
|
|
||||||
</v-fade-transition>
|
</v-fade-transition>
|
||||||
<v-spacer />
|
<v-spacer />
|
||||||
<v-fade-transition
|
<v-fade-transition
|
||||||
mode="out-in"
|
mode="out-in"
|
||||||
>
|
>
|
||||||
<div :key="$route.meta.title">
|
<v-layout
|
||||||
|
:key="$route.meta.title"
|
||||||
|
class="flex-shrink-0 flex-grow-0"
|
||||||
|
justify-end
|
||||||
|
>
|
||||||
<template v-if="creature">
|
<template v-if="creature">
|
||||||
<shared-icon :model="creature" />
|
<shared-icon :model="creature" />
|
||||||
<v-menu
|
<v-menu
|
||||||
@@ -68,7 +70,7 @@
|
|||||||
</v-menu>
|
</v-menu>
|
||||||
<v-app-bar-nav-icon @click="toggleRightDrawer" />
|
<v-app-bar-nav-icon @click="toggleRightDrawer" />
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</v-layout>
|
||||||
</v-fade-transition>
|
</v-fade-transition>
|
||||||
<v-fade-transition
|
<v-fade-transition
|
||||||
slot="extension"
|
slot="extension"
|
||||||
|
|||||||
@@ -20,7 +20,51 @@
|
|||||||
lg="6"
|
lg="6"
|
||||||
>
|
>
|
||||||
<v-card class="pb-4">
|
<v-card class="pb-4">
|
||||||
<v-card-title>Slots</v-card-title>
|
<v-card-title style="height: 68px;">
|
||||||
|
Slots
|
||||||
|
<v-spacer />
|
||||||
|
<v-scale-transition>
|
||||||
|
<v-menu
|
||||||
|
bottom
|
||||||
|
left
|
||||||
|
>
|
||||||
|
<template #activator="{ on }">
|
||||||
|
<v-badge
|
||||||
|
v-show="hiddenCount"
|
||||||
|
slot="activator"
|
||||||
|
color="primary"
|
||||||
|
overlap
|
||||||
|
:value="hiddenCount"
|
||||||
|
:content="hiddenCount"
|
||||||
|
>
|
||||||
|
<v-btn
|
||||||
|
icon
|
||||||
|
v-on="on"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-file-hidden</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</v-badge>
|
||||||
|
</template>
|
||||||
|
<v-list>
|
||||||
|
<v-subheader>
|
||||||
|
<v-icon class="mr-2">
|
||||||
|
mdi-file-hidden
|
||||||
|
</v-icon>
|
||||||
|
{{ hiddenCount }} hidden {{ hiddenCount > 1 ? 'slots' : 'slot' }}
|
||||||
|
</v-subheader>
|
||||||
|
<v-list-item
|
||||||
|
v-for="slot in hiddenSlots"
|
||||||
|
:key="slot._id"
|
||||||
|
@click="unhideSlot(slot._id)"
|
||||||
|
>
|
||||||
|
<v-list-item-title>
|
||||||
|
{{ getPropertyTitle(slot) }}
|
||||||
|
</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
|
</v-scale-transition>
|
||||||
|
</v-card-title>
|
||||||
<build-tree-node-list
|
<build-tree-node-list
|
||||||
:children="slotBuildTree"
|
:children="slotBuildTree"
|
||||||
class="mx-2"
|
class="mx-2"
|
||||||
@@ -135,6 +179,9 @@ import SlotCardsToFill from '/imports/ui/creature/slots/SlotCardsToFill.vue';
|
|||||||
import CreatureVariables from '../../../../api/creature/creatures/CreatureVariables';
|
import CreatureVariables from '../../../../api/creature/creatures/CreatureVariables';
|
||||||
import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js';
|
import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js';
|
||||||
import CharacterErrors from '/imports/ui/creature/character/errors/CharacterErrors.vue';
|
import CharacterErrors from '/imports/ui/creature/character/errors/CharacterErrors.vue';
|
||||||
|
import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
|
||||||
|
import updateCreatureProperty from '/imports/api/creature/creatureProperties/methods/updateCreatureProperty.js';
|
||||||
|
import getPropertyTitle from '/imports/ui/properties/shared/getPropertyTitle.js';
|
||||||
|
|
||||||
function traverse(tree, callback, parents = []){
|
function traverse(tree, callback, parents = []){
|
||||||
tree.forEach(node => {
|
tree.forEach(node => {
|
||||||
@@ -179,7 +226,10 @@ export default {
|
|||||||
...this.highestLevels,
|
...this.highestLevels,
|
||||||
...this.classProperties
|
...this.classProperties
|
||||||
].sort((a, b) => a.order - b.order);
|
].sort((a, b) => a.order - b.order);
|
||||||
}
|
},
|
||||||
|
hiddenCount() {
|
||||||
|
return this.hiddenSlots.length;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
meteor: {
|
meteor: {
|
||||||
creature(){
|
creature(){
|
||||||
@@ -188,6 +238,29 @@ export default {
|
|||||||
variables() {
|
variables() {
|
||||||
return CreatureVariables.findOne({ _creatureId: this.creatureId }) || {};
|
return CreatureVariables.findOne({ _creatureId: this.creatureId }) || {};
|
||||||
},
|
},
|
||||||
|
hiddenSlots(){
|
||||||
|
return CreatureProperties.find({
|
||||||
|
type: 'propertySlot',
|
||||||
|
'ancestors.id': this.creatureId,
|
||||||
|
ignored: true,
|
||||||
|
$and: [
|
||||||
|
{
|
||||||
|
$or: [
|
||||||
|
{'slotCondition.value': {$nin: [false, 0, '']}},
|
||||||
|
{'slotCondition.value': {$exists: false}},
|
||||||
|
]
|
||||||
|
},{
|
||||||
|
$or: [
|
||||||
|
{ 'quantityExpected.value': {$in: [false, 0, '', undefined]} },
|
||||||
|
{ 'quantityExpected.value': {exists: false} },
|
||||||
|
{spaceLeft: {$gt: 0}},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
removed: {$ne: true},
|
||||||
|
inactive: {$ne: true},
|
||||||
|
}).fetch();
|
||||||
|
},
|
||||||
classProperties(){
|
classProperties(){
|
||||||
return CreatureProperties.find({
|
return CreatureProperties.find({
|
||||||
'ancestors.id': this.creatureId,
|
'ancestors.id': this.creatureId,
|
||||||
@@ -313,6 +386,19 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
getPropertyTitle,
|
||||||
|
unhideSlot(_id) {
|
||||||
|
updateCreatureProperty.call({
|
||||||
|
_id,
|
||||||
|
path: ['ignored'],
|
||||||
|
value: false,
|
||||||
|
}, error => {
|
||||||
|
if (error){
|
||||||
|
console.error(error);
|
||||||
|
snackbar({text: error.reason || error.message || error.toString()});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import Vuex from 'vuex';
|
import Vuex from 'vuex';
|
||||||
import dialogStackStore from '/imports/ui/dialogStack/dialogStackStore.js';
|
import dialogStackStore from '/imports/ui/dialogStack/dialogStackStore.js';
|
||||||
|
import Creatures from '/imports/api/creature/creatures/Creatures.js';
|
||||||
|
const tabs = ['stats', 'features', 'inventory', 'spells', 'journal', 'build', 'tree'];
|
||||||
|
const tabsWithoutSpells = ['stats', 'features', 'inventory', 'journal', 'build', 'tree'];
|
||||||
|
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
const store = new Vuex.Store({
|
const store = new Vuex.Store({
|
||||||
@@ -16,13 +19,21 @@ const store = new Vuex.Store({
|
|||||||
showDetailsDialog: false,
|
showDetailsDialog: false,
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
// ...
|
|
||||||
tabById: (state) => (id) => {
|
tabById: (state) => (id) => {
|
||||||
if (id in state.characterSheetTabs){
|
if (id in state.characterSheetTabs){
|
||||||
return state.characterSheetTabs[id];
|
return state.characterSheetTabs[id];
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
tabNameById: (state) => (id) => {
|
||||||
|
const tabNumber = state.characterSheetTabs[id];
|
||||||
|
const creature = Creatures.findOne(id);
|
||||||
|
if (creature?.settings?.hideSpellsTab) {
|
||||||
|
return tabsWithoutSpells[tabNumber];
|
||||||
|
} else {
|
||||||
|
return tabs[tabNumber]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dicecloud",
|
"name": "dicecloud",
|
||||||
"version": "2.0.33",
|
"version": "2.0.38",
|
||||||
"description": "Unofficial Online Realtime D&D 5e App",
|
"description": "Unofficial Online Realtime D&D 5e App",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -11,7 +11,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"run": "meteor",
|
"run": "meteor",
|
||||||
"debug": "meteor --inspect",
|
"debug": "meteor --inspect",
|
||||||
"test": "meteor test --driver-package meteortesting:mocha --port 3001"
|
"test": "meteor test --driver-package meteortesting:mocha --port 3001",
|
||||||
|
"build": "meteor build ../build --architecture os.linux.x86_64"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "14.0.x",
|
"node": "14.0.x",
|
||||||
|
|||||||
Reference in New Issue
Block a user