Added inventory tab

This commit is contained in:
Stefan Zermatten
2020-03-12 15:51:49 +02:00
parent e26031368d
commit d00ff000ce
17 changed files with 129 additions and 580 deletions

View File

@@ -9,7 +9,6 @@ random@1.1.0
dburles:collection-helpers
reactive-var@1.0.11
underscore@1.0.10
matb33:collection-hooks
momentjs:moment
dburles:mongo-collection-instances
percolate:migrations

View File

@@ -60,7 +60,6 @@ livedata@1.0.18
lmieulet:meteor-coverage@1.1.4
localstorage@1.2.0
logging@1.1.20
matb33:collection-hooks@0.9.1
mdg:validated-method@1.2.0
meteor@1.9.3
meteor-base@1.4.0

View File

@@ -45,6 +45,9 @@
Features
</v-tab>
<v-tab>
Inventory
</v-tab>
<v-tab>
Tree
</v-tab>
</v-tabs>
@@ -57,6 +60,9 @@
<v-tab-item>
<features-tab :creature-id="creatureId"/>
</v-tab-item>
<v-tab-item>
<inventory-tab :creature-id="creatureId"/>
</v-tab-item>
<v-tab-item>
<tree-tab :creature-id="creatureId"/>
</v-tab-item>
@@ -74,10 +80,11 @@
import isDarkColor from '/imports/ui/utility/isDarkColor.js';
import { mapMutations } from "vuex";
import { theme } from '/imports/ui/theme.js';
import TreeTab from '/imports/ui/creature/character/characterSheetTabs/TreeTab.vue';
import StatsTab from '/imports/ui/creature/character/characterSheetTabs/StatsTab.vue';
import FeaturesTab from '/imports/ui/creature/character/characterSheetTabs/FeaturesTab.vue';
import { recomputeCreature } from '/imports/api/creature/creatureComputation.js'
import InventoryTab from '/imports/ui/creature/character/characterSheetTabs/InventoryTab.vue';
import TreeTab from '/imports/ui/creature/character/characterSheetTabs/TreeTab.vue';
import { recomputeCreature } from '/imports/api/creature/creatureComputation.js';
export default {
props: {
@@ -85,9 +92,10 @@
creatureId: String,
},
components: {
TreeTab,
StatsTab,
FeaturesTab,
InventoryTab,
TreeTab,
},
data(){return {
theme,

View File

@@ -0,0 +1,50 @@
<template lang="html">
<div class="inventory">
<column-layout>
<div v-for="container in containers" :key="container._id">
<container-card
:model="container"
:items="container.items"
/>
</div>
</column-layout>
</div>
</template>
<script>
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
import ContainerCard from '/imports/ui/properties/components/inventory/ContainerCard.vue';
export default {
props: {
creatureId: String,
},
components: {
ColumnLayout,
ContainerCard,
},
meteor: {
containers(){
return CreatureProperties.find({
'ancestors.id': this.creatureId,
type: 'container',
removed: {$ne: true},
}, {
sort: {order: 1},
}).map(container => {
container.items = CreatureProperties.find({
'parent.id': container._id,
removed: {$ne: true},
}, {
sort: {order: 1},
});
return container;
});
},
},
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,35 +1,23 @@
import AttributeDialog from '/imports/ui/properties/components/attributes/AttributeDialog.vue';
import AttributeDialogContainer from '/imports/ui/properties/components/attributes/AttributeDialogContainer.vue';
import AttributeCreationDialog from '/imports/ui/properties/components/attributes/AttributeCreationDialog.vue';
import CreatureFormDialog from '/imports/ui/creature/CreatureFormDialog.vue';
import CreaturePropertyCreationDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyCreationDialog.vue';
import CreaturePropertyDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyDialog.vue'
import CreaturePropertyFromLibraryDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyFromLibraryDialog.vue'
import DeleteConfirmationDialog from '/imports/ui/dialogStack/DeleteConfirmationDialog.vue';
import FeatureCreationDialog from '/imports/ui/properties/components/features/FeatureCreationDialog.vue';
import FeatureDialogContainer from '/imports/ui/properties/components/features/FeatureDialogContainer.vue';
import LibraryCreationDialog from '/imports/ui/library/LibraryCreationDialog.vue';
import LibraryEditDialog from '/imports/ui/library/LibraryEditDialog.vue';
import LibraryNodeCreationDialog from '/imports/ui/library/LibraryNodeCreationDialog.vue';
import LibraryNodeEditDialog from '/imports/ui/library/LibraryNodeEditDialog.vue';
import ShareDialog from '/imports/ui/sharing/ShareDialog.vue';
import SkillDialogContainer from '/imports/ui/properties/components/skills/SkillDialogContainer.vue';
export default {
AttributeDialog,
AttributeDialogContainer,
AttributeCreationDialog,
CreatureFormDialog,
CreaturePropertyCreationDialog,
CreaturePropertyDialog,
CreaturePropertyFromLibraryDialog,
DeleteConfirmationDialog,
FeatureCreationDialog,
FeatureDialogContainer,
LibraryCreationDialog,
LibraryEditDialog,
LibraryNodeCreationDialog,
LibraryNodeEditDialog,
ShareDialog,
SkillDialogContainer,
};

View File

@@ -1,84 +0,0 @@
<template lang="html">
<dialog-base>
<div slot="toolbar">
New Attribute
</div>
<attribute-edit
:attribute="attribute"
:errors="errors"
@change="change"
:debounce-time="0"
/>
<v-spacer slot="actions"/>
<v-btn
flat
slot="actions"
:disabled="!valid"
@click="$store.dispatch('popDialogStack', attribute)"
>
Insert Attribute
</v-btn>
</dialog-base>
</template>
<script>
import AttributeForm from '/imports/ui/properties/forms/AttributeForm.vue';
import Attributes from '/imports/api/properties/Attributes.js';
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
export default {
components: {
AttributeForm,
DialogBase,
},
data(){ return {
attribute: {
name: 'New Attribute',
variableName: 'newAttribute',
type: 'stat',
baseValue: null,
adjustment: null,
decimal: null,
reset: null,
color: '#9E9E9E',
},
valid: true,
}},
created(){
this.validationContext = Attributes.simpleSchema().newContext();
},
methods: {
change(update, ack){
for (key in update){
this.attribute[key] = update[key];
if (key === 'name' && update[key]){
const name = update[key];
this.attribute.variableName = name.toLowerCase().replace(
/\W+(\w?)/g, (match, p1) => p1.toUpperCase()
);
}
}
if (ack) ack();
},
},
computed: {
errors(){
this.valid = true;
let cleanAtt = this.validationContext.clean(this.attribute)
this.validationContext.validate(cleanAtt, {keys: [
'name', 'variableName', 'type', 'baseValue', 'adjustment', 'decimal',
'reset', 'color'
]});
let errors = {};
this.validationContext.validationErrors().forEach(error => {
if (this.valid) this.valid = false;
errors[error.name] = Attributes.simpleSchema().messageForError(error);
});
return errors;
},
},
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,100 +0,0 @@
<template lang="html">
<dialog-base>
<div slot="toolbar">
{{name}}
</div>
<div>
<v-layout align-center column v-if="type === 'ability'">
<div class="display-3 mod">
{{numberToSignedString(mod)}}
</div>
<div class="display-1 ability-value">
{{value}}
</div>
</v-layout>
<div class="display-3 attribute-value" v-else-if="type === 'healthBar'">
{{value+adjustment}} / {{value}}
</div>
<div class="display-3 attribute-value" v-else-if="type === 'modifier'">
{{numberToSignedString(value)}}
</div>
<div class="display-3 attribute-value" v-else>
{{value}}
</div>
<effect-child-list v-if="attribueBaseEffect" :effects="[attribueBaseEffect]"/>
<div v-if="effects && effects.length">
<h6 class="title">Effects</h6>
<effect-child-list :effects="effects" @click="clickedEffect"/>
</div>
</div>
<div slot="edit">
<attribute-edit :attribute="$props" @change="(update, ack) => $emit('change', update, ack)"/>
</div>
</dialog-base>
</template>
<script>
import DialogBase from "/imports/ui/dialogStack/DialogBase.vue";
import EffectChildList from '/imports/ui/properties/viewers/shared/effects/EffectChildList.vue';
import AttributeForm from '/imports/ui/properties/forms/AttributeForm.vue';
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
export default {
props: {
charId: String,
name: String,
variableName: String,
order: Number,
type: String,
baseValue: Number,
value: Number,
mod: Number,
adjustment: Number,
decimal: Boolean,
reset: String,
resetMultiplier: Number,
color: String,
adjustment: {type: Number, default: 0},
effects: {type: Array, default: () => []},
},
methods: {
numberToSignedString,
clickedEffect(e){
this.$emit('clickedEffect', e);
},
},
computed: {
attribueBaseEffect(){
if (!this.baseValue) return;
return {
_id: 'attributeBaseValue',
name: `${this.name}`,
operation: 'base',
result: this.baseValue,
stat: this.variableName,
enabled: true,
};
},
},
components: {
DialogBase,
EffectChildList,
AttributeForm,
},
};
</script>
<style lang="css" scoped>
.ability-value {
font-weight: 600;
font-size: 24px !important;
color: rgba(0, 0, 0, 0.54);
}
.mod, .ability-value {
text-align: center;
width: 100%;
}
.attribute-value {
text-align: center;
}
</style>

View File

@@ -1,59 +0,0 @@
<template lang="html">
<attribute-dialog
v-bind="attribute"
:effects="effects"
v-on="{clickedEffect, change}"
/>
</template>
<script>
import AttributeDialog from '/imports/ui/properties/components/attributes/AttributeDialog.vue';
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
export default {
components: {
AttributeDialog,
},
props: {
_id: String,
},
meteor: {
attribute(){
return Attributes.findOne(this._id);
},
effects(){
if (!this.attribute) return;
let charId = this.attribute.charId;
let stat = this.attribute.variableName;
return CreatureProperties.find({
'ancestor.id': charId,
type: 'effect',
stat,
enabled: true,
}, {
sort: {order: 1},
}).fetch();
},
},
methods: {
clickedEffect(e){
console.log({TODO: e});
},
change(update, ack){
if (update.name){
setName.call({})
} if (update)
updateAttribute.call({
_id: this._id,
update: {$set: update}
}, error => {
ack(error);
if (error) console.error(error);
});
},
}
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,41 +0,0 @@
<template lang="html">
<feature-form
:feature="feature"
@update="update"
:debounce-time="0"
:errors="errors"
/>
</template>
<script>
import FeatureForm from '/imports/ui/properties/forms/FeatureForm.vue';
import Features, { FeatureSchema } from '/imports/api/properties/Features.js';
export default {
components: {
FeatureForm,
},
data(){ return {
feature: {
name: 'New Feature',
description: null,
enabled: true,
alwaysEnabled: true,
color: '#9E9E9E',
},
schema: FeatureSchema,
errors: {},
}},
methods: {
update(update, ack){
for (key in update){
this.feature[key] = update[key];
}
ack();
},
},
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,29 +0,0 @@
<template lang="html">
<div>
<markdown-text :markdown="feature.computedDescription || feature.description"/>
<!--
<child-lists
:parent="feature"
/>
-->
<feature-form slot="form" :feature="feature" @update="(update, ack) => $emit('update', update, ack)"/>
</div>
</template>
<script>
import FeatureForm from '/imports/ui/properties/forms/FeatureForm.vue';
import MarkdownText from '/imports/ui/components/MarkdownText.vue';
export default {
components: {
FeatureForm,
MarkdownText,
},
props: {
feature: Object,
},
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,42 +0,0 @@
<template lang="html">
<feature-dialog
:feature="feature"
@update="update"
@remove="remove"
/>
</template>
<script>
import Features, {updateFeature} from '/imports/api/properties/Features.js';
import FeatureDialog from '/imports/ui/properties/components/features/FeatureDialog.vue';
import {evaluateStringForCharId} from '/imports/ui/utility/evaluate.js';
export default {
components: {
FeatureDialog,
},
props: {
_id: String,
},
meteor: {
feature(){
let feature = Features.findOne(this._id);
feature.computedDescription = evaluateStringForCharId(
feature.description, feature.charId
);
return feature;
},
},
methods: {
update(update, ack){
updateFeature.call({
_id: this._id,
update,
}, error => ack(error));
},
remove(){
softRemoveProperty({_id: this._id, collection: 'features'});
}
},
};
</script>

View File

@@ -0,0 +1,48 @@
<template lang="html">
<toolbar-card :color="model.color" @click="clickProperty(model._id)" :data-id="model._id">
<template slot="toolbar">
<span>
{{model.name}}
</span>
<v-spacer/>
</template>
<v-list>
<item-list-tile
v-for="item in items"
:model="item"
:key="item._id"
:data-id="item._id"
@click="clickProperty(item._id)"
/>
</v-list>
</toolbar-card>
</template>
<script>
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import ToolbarCard from '/imports/ui/components/ToolbarCard.vue';
import ItemListTile from '/imports/ui/properties/components/inventory/ItemListTile.vue';
export default {
props: {
model: Object,
items: [Array, Object],
},
components: {
ToolbarCard,
ItemListTile,
},
methods: {
clickProperty(_id){
this.$store.commit('pushDialogStack', {
component: 'creature-property-dialog',
elementId: `${_id}`,
data: {_id},
});
},
}
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -0,0 +1,20 @@
<template lang="html">
<v-list-tile class="skill-list-tile" height="32px" v-on="hasClickListener ? {click} : {}">
<v-list-tile-content>
<v-list-tile-title>
{{model.name}}
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</template>
<script>
export default {
props: {
model: Object,
},
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,108 +0,0 @@
<template lang="html">
<dialog-base class="skill-dialog">
<div slot="toolbar">
{{name}}
</div>
<div>
<v-layout align-center justify-center>
<skill-list-tile v-bind="$props"/>
</v-layout>
<skill-proficiency-list v-if="skillBaseProficiency" :effects="[skillBaseProficiency]"/>
<effect-child-list v-if="skillAbilityEffect" :effects="[skillAbilityEffect]"/>
<effect-child-list v-if="skillBaseEffect" :effects="[skillBaseEffect]"/>
<div v-if="proficiencies && proficiencies.length">
<h6 class="title">Proficiencies</h6>
<skill-proficiency-list :proficiencies="proficiencies" @click="clickedProficiency"/>
</div>
<div v-if="effects && effects.length">
<h6 class="title">Effects</h6>
<effect-child-list :effects="effects" @click="clickedEffect"/>
</div>
</div>
<div slot="edit">
<skill-edit :skill="$props" @change="(update, ack) => $emit('change', update, ack)"/>
</div>
</dialog-base>
</template>
<script>
import EffectChildList from '/imports/ui/properties/viewers/shared/effects/EffectChildList.vue';
import DialogBase from "/imports/ui/dialogStack/DialogBase.vue";
import SkillEdit from '/imports/ui/properties/components/skills/SkillEdit.vue';
import SkillProficiencyList from '/imports/ui/properties/components/skills/SkillProficiencyList.vue';
import SkillListTile from '/imports/ui/properties/components/skills/SkillListTile.vue';
export default {
components: {
EffectChildList,
DialogBase,
SkillEdit,
SkillListTile,
SkillProficiencyList,
},
props: {
charId: String,
name: String,
variableName: String,
ability: String,
type: String,
order: Number,
baseValue: Number,
baseProficiency: Number,
value: Number,
abilityMod: Number,
advantage: Number,
passiveBonus: Number,
proficiency: Number,
conditionalBenefits: Number,
fail: Number,
effects: {
type: Array,
default: () => [],
},
proficiencies: {
type: Array,
default: () => [],
},
abilityDoc: Object,
},
computed: {
skillBaseEffect(){
if (!this.baseValue) return;
return {
_id: 'skillBaseValue',
name: `${this.name}`,
operation: 'base',
result: this.baseValue,
stat: this.variableName,
enabled: true,
};
},
skillAbilityEffect(){
if (!this.abilityDoc) return;
return {
_id: 'skillBaseValue',
name: this.abilityDoc.name,
operation: 'add',
result: this.abilityMod,
stat: this.variableName,
enabled: true,
};
},
skillBaseProficiency(){
if (!this.baseProficiency) return;
return {
_id: 'skillBaseValue',
name: `${this.name}`,
value: this.baseProficiency,
skill: this.variableName,
enabled: true,
};
},
},
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,78 +0,0 @@
<template lang="html">
<skill-dialog
v-bind="skill"
:effects="effects"
:proficiencies="proficiencies"
:abilityDoc="abilityDoc"
v-on="{clickedEffect, clickedProficiency, change}"
/>
</template>
<script>
import SkillDialog from '/imports/ui/properties/components/skills/SkillDialog.vue';
import Skills from '/imports/api/properties/Skills.js';
import { updateSkill } from '/imports/api/properties/Skills.js';
import Attributes from '/imports/api/properties/Attributes.js';
import Effects from '/imports/api/properties/Effects.js';
import Proficiencies from '/imports/api/properties/Proficiencies.js';
export default {
components: {
SkillDialog,
},
props: {
_id: String,
},
meteor: {
skill(){
return Skills.findOne(this._id);
},
abilityDoc(){
return this.skill && Attributes.findOne({
variableName: this.skill.ability,
});
},
effects(){
if (!this.skill) return;
let charId = this.skill.charId;
let stat = this.skill.variableName;
return Effects.find({
charId,
stat,
enabled: true,
}, {
sort: {order: 1},
}).fetch();
},
proficiencies(){
if (!this.skill) return;
let charId = this.skill.charId;
let stat = this.skill.variableName;
return Proficiencies.find({
charId,
stat,
enabled: true,
}, {
sort: {order: 1},
}).fetch();
},
},
methods: {
clickedEffect(e){
console.log(e);
},
clickedProficiency(e){
console.log(e);
},
change(update, ack){
updateSkill.call({_id: this._id, update}, error => {
ack(error);
});
},
}
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,11 +0,0 @@
<template lang="html">
<div>Todo</div>
</template>
<script>
export default {
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,11 +0,0 @@
<template lang="html">
<div>TODO</div>
</template>
<script>
export default {
}
</script>
<style lang="css" scoped>
</style>