Improved spell appearance in spell tab

This commit is contained in:
Stefan Zermatten
2020-06-23 01:36:48 +02:00
parent e572807082
commit 2af687361e
7 changed files with 157 additions and 54 deletions

View File

@@ -5,16 +5,23 @@ export default function getActiveProperties({
ancestorId,
filter = {},
options,
includeUntoggled = false
includeUntoggled = false,
excludeAncestors,
}){
filter = getActivePropertyFilter({ancestorId, filter, includeUntoggled});
filter = getActivePropertyFilter({
ancestorId,
filter,
includeUntoggled,
excludeAncestors,
});
return CreatureProperties.find(filter, options).fetch();
}
export function getActivePropertyFilter({
ancestorId,
filter = {},
includeUntoggled = false
includeUntoggled = false,
excludeAncestors = [],
}){
if (!ancestorId){
throw 'Ancestor Id is required to get active properties'
@@ -47,9 +54,12 @@ export function getActivePropertyFilter({
// Get all the properties that are decendents of the ancestor of interest but
// aren't from the excluded decendents
if (filter['ancestors.id'] && Meteor.isClient){
console.warn('Filtering on ancestor id is ignored')
}
filter['ancestors.id'] = {
$eq: ancestorId,
$nin: disabledAncestorIds,
$nin: disabledAncestorIds.concat(excludeAncestors),
};
// Get properties that aren't removed
filter.removed = {$ne: true};

View File

@@ -1,5 +1,6 @@
import SimpleSchema from 'simpl-schema';
import ErrorSchema from '/imports/api/properties/subSchemas/ErrorSchema.js';
import VARIABLE_NAME_REGEX from '/imports/constants/VARIABLE_NAME_REGEX.js';
let SpellListSchema = new SimpleSchema({
name: {
@@ -10,6 +11,12 @@ let SpellListSchema = new SimpleSchema({
type: String,
optional: true,
},
variableName: {
type: String,
regEx: VARIABLE_NAME_REGEX,
min: 2,
optional: true,
},
// Calculation of how many spells in this list can be prepared
maxPrepared: {
type: String,

View File

@@ -1,5 +1,6 @@
import { ActionSchema, ComputedOnlyActionSchema } from '/imports/api/properties/Actions.js';
import SimpleSchema from 'simpl-schema';
import VARIABLE_NAME_REGEX from '/imports/constants/VARIABLE_NAME_REGEX.js';
const magicSchools = [
'abjuration',
@@ -38,13 +39,15 @@ let SpellSchema = new SimpleSchema({})
type: Boolean,
optional: true,
},
// Spell lists that this spell appears on
// Spell list that this spell appears on
spellLists: {
type: Array,
defaultValue: [],
},
'spellLists.$': {
type: String,
regEx: VARIABLE_NAME_REGEX,
min: 2,
},
description: {
type: String,

View File

@@ -1,27 +1,20 @@
<template lang="html">
<div class="spells">
<column-layout>
<column-layout wide-columns>
<div>
<v-card>
<v-card-text>
<v-switch
v-if="context.editPermission !== false"
v-model="organize"
label="Organize"
class="justify-end"
<v-list
two-line
dense
>
<spell-list-tile
v-for="spell in spellsWithoutList"
:key="spell._id"
:data-id="`spell-list-tile-${spell._id}`"
:model="spell"
@click="clickProperty(spell._id)"
/>
<creature-properties-tree
:root="{collection: 'creatures', id: creatureId}"
:filter="{
equipped: {$ne: true},
type: 'spell',
'ancestors.id': {$nin: spellListIds}
}"
:organize="organize"
group="spells"
@selected="e => clickProperty(e)"
/>
</v-card-text>
</v-list>
</v-card>
</div>
<div
@@ -41,12 +34,15 @@
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
import CreaturePropertiesTree from '/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue';
import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
import SpellListCard from '/imports/ui/properties/components/spells/SpellListCard.vue';
import SpellListTile from '/imports/ui/properties/components/spells/SpellListTile.vue';
export default {
components: {
ColumnLayout,
CreaturePropertiesTree,
SpellListTile,
SpellListCard,
},
inject: {
@@ -63,25 +59,30 @@ export default {
}},
meteor: {
spellLists(){
return CreatureProperties.find({
'ancestors.id': this.creatureId,
type: 'spellList',
removed: {$ne: true},
}, {
sort: {order: 1},
});
return getActiveProperties({
ancestorId: this.creatureId,
filter: {
type: 'spellList',
},
});
},
spellsWithoutList(){
return getActiveProperties({
ancestorId: this.creatureId,
excludeAncestors: this.spellListIds,
filter: {
type: 'spell',
},
});
},
spellListsWithoutAncestorSpellLists(){
return CreatureProperties.find({
'ancestors.id': {
$eq: this.creatureId,
$nin: this.spellListIds
},
type: 'spellList',
removed: {$ne: true},
}, {
sort: {order: 1},
});
return getActiveProperties({
ancestorId: this.creatureId,
excludeAncestors: this.spellListIds,
filter: {
type: 'spellList',
},
});
},
},
computed: {
@@ -93,7 +94,7 @@ export default {
clickProperty(_id){
this.$store.commit('pushDialogStack', {
component: 'creature-property-dialog',
elementId: `tree-node-${_id}`,
elementId: `spell-list-tile-${_id}`,
data: {_id},
});
},

View File

@@ -10,32 +10,45 @@
</v-toolbar-title>
<v-spacer />
</template>
<v-card-text>
<creature-properties-tree
:root="{collection: 'creatureProperties', id: model._id}"
:filter="{type: {$in: ['spellList', 'spell', 'folder']}}"
:organize="organize"
group="spells"
@selected="e => clickProperty(e)"
<v-list
two-line
dense
>
<spell-list-tile
v-for="spell in spells"
:key="spell._id"
:data-id="`spell-list-tile-${spell._id}`"
:model="spell"
@click="clickProperty(spell._id)"
/>
</v-card-text>
</v-list>
</toolbar-card>
</template>
<script>
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import ToolbarCard from '/imports/ui/components/ToolbarCard.vue';
import CreaturePropertiesTree from '/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue';
import SpellListTile from '/imports/ui/properties/components/spells/SpellListTile.vue';
import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
export default {
components: {
ToolbarCard,
CreaturePropertiesTree,
SpellListTile,
},
props: {
model: Object,
organize: Boolean,
},
meteor: {
spells(){
return getActiveProperties({
ancestorId: this.model._id,
filter: {
type: 'spell',
},
});
},
},
methods: {
clickSpellList(_id){
this.$store.commit('pushDialogStack', {
@@ -47,7 +60,7 @@ export default {
clickProperty(_id){
this.$store.commit('pushDialogStack', {
component: 'creature-property-dialog',
elementId: `tree-node-${_id}`,
elementId: `spell-list-tile-${_id}`,
data: {_id},
});
},

View File

@@ -0,0 +1,61 @@
<template lang="html">
<v-list-tile
v-on="hasClickListener ? {click} : {}"
>
<v-list-tile-avatar class="spell-avatar">
<property-icon
class="mr-2"
:model="model"
:color="model.color"
/>
</v-list-tile-avatar>
<v-list-tile-content>
<v-list-tile-title>
{{ title }}
</v-list-tile-title>
<v-list-tile-sub-title v-if="components">
{{ components }}
</v-list-tile-sub-title>
</v-list-tile-content>
<v-list-tile-action>
<v-list-tile-action-text>
{{ levelText }}
</v-list-tile-action-text>
</v-list-tile-action>
</v-list-tile>
</template>
<script>
import treeNodeViewMixin from '/imports/ui/properties/treeNodeViews/treeNodeViewMixin.js';
export default {
mixins: [treeNodeViewMixin],
computed: {
hasClickListener(){
return this.$listeners && !!this.$listeners.click;
},
components(){
let components = [];
if (this.model.ritual) components.push('R');
if (this.model.concentration) components.push('C');
if (this.model.verbal) components.push('V');
if (this.model.somatic) components.push('S');
if (this.model.material) components.push(`M (${this.model.material})`);
return components.join(', ');
},
levelText(){
return this.model.level || 'Cantrip'
},
},
methods: {
click(e){
this.$emit('click', e);
},
},
}
</script>
<style lang="css" scoped>
.spell-avatar {
min-width: 32px;
}
</style>

View File

@@ -8,6 +8,14 @@
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
<text-field
label="Variable name"
:value="model.variableName"
style="flex-basis: 300px;"
hint="This name is used by spells to reference which lists they appear on"
:error-messages="errors.variableName"
@change="change('variableName', ...arguments)"
/>
</div>
<text-area
label="Description"