Added big slot cards to build tab, improved build tab

This commit is contained in:
Stefan Zermatten
2022-06-07 21:43:35 +02:00
parent a04935c5b4
commit 385ac17812
13 changed files with 228 additions and 248 deletions

View File

@@ -44,8 +44,8 @@ const restCreature = new ValidatedMethod({
let filter = {
'ancestors.id': creatureId,
reset: resetFilter,
removed: {$ne: true},
inactive: {$ne: true},
removed: { $ne: true },
inactive: { $ne: true },
};
// update all attribute's damage
filter.type = 'attribute';

View File

@@ -6,7 +6,7 @@ import writeErrors from './computation/writeComputation/writeErrors.js';
export default function computeCreature(creatureId){
if (Meteor.isClient) return;
console.log('compute')
// console.log('compute ' + creatureId);
const computation = buildCreatureComputation(creatureId);
computeComputation(computation, creatureId);
}

View File

@@ -2,6 +2,8 @@ import { debounce } from 'lodash';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
import Creatures from '/imports/api/creature/creatures/Creatures.js';
import computeCreature from './computeCreature';
const COMPUTE_DEBOUNCE_TIME = 100; // ms
export const loadedCreatures = new Map(); // creatureId => {creature, properties, etc.}
export function loadCreature(creatureId, subscription) {
@@ -40,7 +42,7 @@ class LoadedCreature {
const compute = debounce(Meteor.bindEnvironment(() => {
computeCreature(creatureId);
}), 100);
}), COMPUTE_DEBOUNCE_TIME);
self.properties = new Map();
// Observe all creature properties which are needed for computation

View File

@@ -18,7 +18,7 @@
props: {
active: Boolean,
dark: Boolean,
}
},
}
</script>

View File

@@ -4,7 +4,7 @@
:class="{
'empty': !hasChildren,
}"
:data-id="`tree-node-${node._id}`"
:data-id="`build-tree-node-${node._id}`"
>
<div
class="layout align-center justify-start tree-node-title"
@@ -50,7 +50,6 @@
<tree-node-view
v-else
:model="node"
:hide-icon="node.type === 'propertySlot'"
/>
<template v-if="condenseChild">
<span class="mr-4">:</span>
@@ -69,6 +68,7 @@
<build-tree-node-list
v-if="showExpanded"
:children="computedChildren"
@selected="e => $emit('selected', e)"
/>
<div v-else>
<div
@@ -119,15 +119,22 @@
},
},
data(){return {
expanded: this.node._descendantCanFill || (
this.node.type === 'propertySlot' &&
this. node.quantityExpected?.value === 0 ||
(this.node.quantityExpected?.value > 1 && this.node.spaceLeft > 0)
),
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;
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';

View File

@@ -4,7 +4,7 @@
icon
:data-id="`slot-add-button-${model._id}`"
class="slot-add-button accent--text"
@click="fillSlot()"
@click.stop="fillSlot()"
>
<v-icon>mdi-plus</v-icon>
</v-btn>

View File

@@ -1,13 +1,30 @@
<template lang="html">
<v-container fluid>
<v-row dense>
<v-col cols="12" md="8" lg="6" style="height: 100%;">
<v-card style="height: calc(100vh - 120px); overflow: auto;">
<v-col cols="12">
<slot-cards-to-fill :creature-id="creatureId" />
</v-col>
</v-row>
<v-row dense>
<v-col
cols="12"
md="8"
lg="6"
>
<v-card class="pb-4">
<v-card-title>Slots</v-card-title>
<build-tree-node-list :children="slotBuildTree" />
<build-tree-node-list
:children="slotBuildTree"
class="mx-2"
@selected="_id => propertyClicked({_id, prefix: 'build-tree-node-'})"
/>
</v-card>
</v-col>
<v-col cols="12" md="4" lg="6">
<v-col
cols="12"
md="4"
lg="6"
>
<v-card class="class-details mb-2">
<v-card-title
v-if="creature.variables.level"
@@ -75,29 +92,6 @@
</v-list-item>
</v-list>
</v-card>
<toolbar-card
data-id="slot-card"
@toolbarclick="showSlotDialog"
>
<template slot="toolbar">
<v-toolbar-title>
Build
</v-toolbar-title>
<v-spacer />
<v-toolbar-title>
<v-icon
small
style="width: 16px;"
class="mr-1"
>
mdi-pencil
</v-icon>
</v-toolbar-title>
</template>
<v-card-text style="background-color: inherit;">
<slots :creature-id="creatureId" />
</v-card-text>
</toolbar-card>
</v-col>
</v-row>
</v-container>
@@ -106,11 +100,9 @@
<script lang="js">
import Creatures from '/imports/api/creature/creatures/Creatures.js';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
import Slots from '/imports/ui/creature/slots/Slots.vue';
import ToolbarCard from '/imports/ui/components/ToolbarCard.vue';
import { nodeArrayToTree } from '/imports/api/parenting/nodesToTree.js';
import { nodeArrayToTree } from '/imports/api/parenting/nodesToTree.js';
import BuildTreeNodeList from '/imports/ui/creature/buildTree/BuildTreeNodeList.vue';
import SlotCardsToFill from '/imports/ui/creature/slots/SlotCardsToFill.vue';
function traverse(tree, callback, parents = []){
tree.forEach(node => {
@@ -121,10 +113,8 @@ function traverse(tree, callback, parents = []){
export default {
components: {
ColumnLayout,
Slots,
ToolbarCard,
BuildTreeNodeList,
SlotCardsToFill,
},
props: {
creatureId: {
@@ -214,6 +204,13 @@ export default {
},
},
methods: {
propertyClicked({_id, prefix}){
this.$store.commit('pushDialogStack', {
component: 'creature-property-dialog',
elementId: `${prefix}${_id}`,
data: {_id},
});
},
addExperience(){
this.$store.commit('pushDialogStack', {
component: 'experience-insert-dialog',

View File

@@ -19,8 +19,6 @@
<script lang="js">
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
import Creatures from '/imports/api/creature/creatures/Creatures.js';
import Slots from '/imports/ui/creature/slots/Slots.vue';
import ToolbarCard from '/imports/ui/components/ToolbarCard.vue';
import NoteCard from '/imports/ui/properties/components/persona/NoteCard.vue';
import CreatureSummary from '/imports/ui/creature/character/CreatureSummary.vue';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';

View File

@@ -0,0 +1,70 @@
<template>
<v-card
v-if="model"
v-bind="$attrs"
:data-id="`slot-card-${model._id}`"
:style="`border: solid 1px ${accentColor};`"
hover
class="slot-card d-flex flex-column"
style="max-width: 400px;"
@mouseover="hover = true"
@mouseleave="hover = false"
@click="$emit('click')"
>
<card-highlight
:active="hover"
/>
<v-card-title>
{{ model.name }}
</v-card-title>
<v-card-text v-if="model.description">
{{ model.description.value }}
</v-card-text>
<v-spacer />
<v-card-actions>
<v-spacer />
<v-btn
text
color="primary"
@click.stop="$emit('ignore')"
>
Skip
</v-btn>
</v-card-actions>
</v-card>
</template>
<script lang="js">
import CardHighlight from '/imports/ui/components/CardHighlight.vue';
export default {
components: {
CardHighlight,
},
inject: {
theme: {
default: {
isDark: false,
},
},
},
props: {
model: {
type: Object,
default: undefined,
},
},
data(){ return {
hover: false,
}},
computed: {
accentColor(){
if (this.theme.isDark){
return this.$vuetify.theme.themes.dark.primary;
} else {
return this.$vuetify.theme.themes.light.primary;
}
}
},
}
</script>

View File

@@ -0,0 +1,104 @@
<template>
<div class="slots-to-fill">
<v-slide-y-transition
group
class="d-flex flex-row flex-wrap"
>
<slot-card
v-for="slot in slots"
:key="slot._id"
:model="slot"
class="ma-1"
hover
@ignore="ignoreSlot(slot._id)"
@click="fillSlot(slot._id)"
/>
</v-slide-y-transition>
</div>
</template>
<script lang="js">
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
import SlotCard from '/imports/ui/creature/slots/SlotCard.vue';
import updateCreatureProperty from '/imports/api/creature/creatureProperties/methods/updateCreatureProperty.js';
import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js';
import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
export default {
components: {
SlotCard,
},
inject: {
context: { default: {} }
},
methods: {
ignoreSlot(_id){
updateCreatureProperty.call({
_id,
path: ['ignored'],
value: true
}, error => {
if (error){
console.error(error);
snackbar(error);
}
});
},
fillSlot(slotId){
this.$store.commit('pushDialogStack', {
component: 'slot-fill-dialog',
elementId: `slot-card-${slotId}`,
data: {
slotId,
creatureId: this.context.creatureId,
},
callback(nodeIds){
if (!nodeIds || !nodeIds.length) return;
let newPropertyId = insertPropertyFromLibraryNode.call({
nodeIds,
parentRef: {
'id': slotId,
'collection': 'creatureProperties',
},
}, error => {
if (error){
console.error(error);
snackbar(error);
}
});
return `slot-child-${newPropertyId}`;
}
});
},
},
meteor: {
slots(){
return CreatureProperties.find({
type: 'propertySlot',
'ancestors.id': this.context.creatureId,
ignored: { $ne: true },
$and: [
{
$or: [
{'slotCondition.value': {$nin: [false, 0, '']}},
{'slotCondition.value': {$exists: false}},
]
},{
$or: [
{ quantityExpected: {exists: false} },
{ 'quantityExpected.value': 0 },
{spaceLeft: {$gt: 0}},
]
},
],
removed: {$ne: true},
inactive: {$ne: true},
});
}
}
}
</script>
<style>
</style>

View File

@@ -1,36 +0,0 @@
<template lang="html">
<dialog-base>
<v-toolbar-title slot="toolbar">
Build
</v-toolbar-title>
<slots
:creature-id="creatureId"
show-hidden-slots
/>
</dialog-base>
</template>
<script lang="js">
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
import Slots from '/imports/ui/creature/slots/Slots.vue'
export default {
components: {
DialogBase,
Slots,
},
props: {
creatureId: {
type: String,
required: true,
},
},
reactiveProvide: {
name: 'context',
include: ['creatureId'],
},
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,160 +0,0 @@
<template lang="html">
<div class="slots">
<div
v-for="slot in slots"
:key="slot._id"
class="slot"
>
<h3 class="layout align-center">
{{ slot.name }}
<v-spacer />
<span v-if="slot.quantityExpected && slot.quantityExpected.value > 1">
{{ slot.totalFilled }} / {{ slot.quantityExpected.value }}
</span>
</h3>
<v-list v-if="slot.children.length">
<v-list-item
v-for="child in slot.children"
:key="child._id"
:data-id="`slot-child-${child._id}`"
@click="clickSlotChild(child)"
>
<v-list-item-content>
<tree-node-view
class="slotChild"
:model="child"
/>
</v-list-item-content>
<v-list-item-action>
<v-btn
icon
small
@click.stop="remove(child)"
>
<v-icon>mdi-delete</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list>
<v-btn
v-if="!slot.quantityExpected || !slot.quantityExpected.value || slot.spaceLeft"
icon
:data-id="`slot-add-button-${slot._id}`"
class="slot-add-button"
style="background-color: inherit;"
@click="fillSlot(slot)"
>
<v-icon>mdi-plus</v-icon>
</v-btn>
</div>
</div>
</template>
<script lang="js">
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
import TreeNodeView from '/imports/ui/properties/treeNodeViews/TreeNodeView.vue';
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';
import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js';
import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
export default {
components: {
TreeNodeView,
},
props: {
creatureId: {
type: String,
required: true,
},
showHiddenSlots: {
type: Boolean,
},
},
methods: {
clickSlotChild({_id}){
this.$store.commit('pushDialogStack', {
component: 'creature-property-dialog',
elementId: `slot-child-${_id}`,
data: {_id},
});
},
fillSlot(slot){
let slotId = slot._id;
let creatureId = this.creatureId;
this.$store.commit('pushDialogStack', {
component: 'slot-fill-dialog',
elementId: `slot-add-button-${slotId}`,
data: {
slotId,
creatureId,
},
callback(nodeIds){
if (!nodeIds || !nodeIds.length) return;
let newPropertyId = insertPropertyFromLibraryNode.call({
nodeIds,
parentRef: {
'id': slotId,
'collection': 'creatureProperties',
},
});
return `slot-child-${newPropertyId}`;
}
});
},
remove(model){
softRemoveProperty.call({_id: model._id});
snackbar({
text: `Deleted ${getPropertyTitle(model)}`,
callbackName: 'undo',
callback(){
restoreProperty.call({_id: model._id});
},
});
}
},
meteor: {
slots(){
return CreatureProperties.find({
'ancestors.id': this.creatureId,
type: 'propertySlot',
$or: [
{'slotCondition.value': {$nin: [false, 0, '']}},
{'slotCondition.value': {$exists: false}},
],
removed: {$ne: true},
inactive: {$ne: true},
}, {
sort: {order: 1}
}).map(slot => {
if (
!this.showHiddenSlots &&
(slot.quantityExpected && slot.quantityExpected.value) === 0 &&
slot.hideWhenFull
){
slot.children = []
} else {
slot.children = CreatureProperties.find({
'parent.id': slot._id,
removed: {$ne: true},
}, {
sort: { order: 1 },
}).fetch();
}
return slot;
}).filter(slot => !( // Hide full and ignored slots
!this.showHiddenSlots && (
slot.hideWhenFull &&
(slot.quantityExpected && slot.quantityExpected.value) > 0 &&
slot.spaceLeft <= 0 ||
slot.ignored
)
));
},
},
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -18,7 +18,6 @@ const MoveLibraryNodeDialog = () => import('/imports/ui/library/MoveLibraryNodeD
const SelectCreaturesDialog = () => import('/imports/ui/tabletop/SelectCreaturesDialog.vue');
const SelectLibraryNodeDialog = () => import('/imports/ui/library/SelectLibraryNodeDialog.vue');
const ShareDialog = () => import('/imports/ui/sharing/ShareDialog.vue');
const SlotDetailsDialog = () => import('/imports/ui/creature/slots/SlotDetailsDialog.vue');
const SlotFillDialog = () => import('/imports/ui/creature/slots/SlotFillDialog.vue');
const TierTooLowDialog = () => import('/imports/ui/user/TierTooLowDialog.vue');
const TransferOwnershipDialog = () => import('/imports/ui/sharing/TransferOwnershipDialog.vue');
@@ -45,7 +44,6 @@ export default {
SelectCreaturesDialog,
SelectLibraryNodeDialog,
ShareDialog,
SlotDetailsDialog,
SlotFillDialog,
TierTooLowDialog,
TransferOwnershipDialog,