Improved spell slot casting dialog with search, filters, spell details
This commit is contained in:
@@ -26,6 +26,10 @@ export default {
|
||||
value: [String, Number, Date, Array, Object, Boolean],
|
||||
errorMessages: [String, Array],
|
||||
disabled: Boolean,
|
||||
debounce: {
|
||||
type: Number,
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
focused(newFocus){
|
||||
@@ -113,7 +117,9 @@ export default {
|
||||
return this.context.editPermission === false || this.disabled;
|
||||
},
|
||||
debounceTime() {
|
||||
if (Number.isFinite(this.context.debounceTime)){
|
||||
if (Number.isFinite(this.debounce)){
|
||||
return this.debounce;
|
||||
} else if (Number.isFinite(this.context.debounceTime)){
|
||||
return this.context.debounceTime;
|
||||
} else {
|
||||
return 750;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
:error-messages="errors"
|
||||
:value="safeValue"
|
||||
:disabled="isDisabled"
|
||||
box
|
||||
:box="!regular"
|
||||
@input="input"
|
||||
@focus="focused = true"
|
||||
@blur="focused = false"
|
||||
@@ -18,5 +18,8 @@
|
||||
|
||||
export default {
|
||||
mixins: [SmartInput],
|
||||
props: {
|
||||
regular: Boolean,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,66 @@
|
||||
Cast a Spell
|
||||
</v-toolbar-title>
|
||||
<v-spacer />
|
||||
<v-input icon="search" />
|
||||
<text-field
|
||||
ref="focusFirst"
|
||||
label="Name"
|
||||
prepend-inner-icon="search"
|
||||
regular
|
||||
hide-details
|
||||
:value="searchValue"
|
||||
:error-messages="searchError"
|
||||
:debounce="200"
|
||||
@change="searchChanged"
|
||||
/>
|
||||
<v-menu
|
||||
v-model="filterMenuOpen"
|
||||
left
|
||||
:close-on-content-click="false"
|
||||
>
|
||||
<template #activator="{ on }">
|
||||
<v-btn
|
||||
icon
|
||||
flat
|
||||
:class="{'primary--text': filtersApplied}"
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>filter_list</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-list>
|
||||
<v-list-tile
|
||||
v-for="filter in booleanFilters"
|
||||
:key="filter.name"
|
||||
style="height: 52px;"
|
||||
>
|
||||
<v-checkbox
|
||||
v-model="filter.enabled"
|
||||
style="flex-grow: 0; margin-right: 8px;"
|
||||
/>
|
||||
<v-switch
|
||||
v-model="filter.value"
|
||||
:disabled="!filter.enabled"
|
||||
:label="filter.name"
|
||||
/>
|
||||
</v-list-tile>
|
||||
<div class="layout row">
|
||||
<v-btn
|
||||
flat
|
||||
@click="clearBooleanFilters"
|
||||
>
|
||||
Clear
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
flat
|
||||
class="primary--text"
|
||||
@click="filterMenuOpen = false"
|
||||
>
|
||||
Done
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
<split-list-layout>
|
||||
<template slot="left">
|
||||
@@ -56,9 +115,11 @@
|
||||
v-else
|
||||
:key="spell._id"
|
||||
hide-handle
|
||||
show-info-button
|
||||
:class="{ 'primary--text': selectedSpellId === spell._id}"
|
||||
:model="spell"
|
||||
@click="selectedSpellId = spell._id"
|
||||
@show-info="spellDialog(spell._id)"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
@@ -119,6 +180,16 @@ export default {
|
||||
searchString: undefined,
|
||||
selectedSlotId: this.slotId,
|
||||
selectedSpellId: this.spellId,
|
||||
searchValue: undefined,
|
||||
searchError: undefined,
|
||||
filterMenuOpen: false,
|
||||
booleanFilters: {
|
||||
verbal: {name: 'Verbal', enabled: false, value: false},
|
||||
somatic: {name: 'Somatic', enabled: false, value: false},
|
||||
material: {name: 'Material', enabled: false, value: false},
|
||||
concentration: {name: 'Concentration', enabled: false, value: false},
|
||||
ritual: {name: 'Ritual', enabled: false, value: false},
|
||||
},
|
||||
}},
|
||||
computed: {
|
||||
computedSpells(){
|
||||
@@ -135,7 +206,15 @@ export default {
|
||||
} else {
|
||||
return slot.spellSlotLevelValue >= spell.level;
|
||||
}
|
||||
}
|
||||
},
|
||||
filtersApplied(){
|
||||
for (let key in this.booleanFilters){
|
||||
if (this.booleanFilters[key].enabled){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selectedSpell(spell){
|
||||
@@ -152,16 +231,53 @@ export default {
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clearBooleanFilters(){
|
||||
for (let key in this.booleanFilters){
|
||||
this.booleanFilters[key].enabled = false;
|
||||
}
|
||||
},
|
||||
spellDialog(_id){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `spell-info-btn-${_id}`,
|
||||
data: {_id},
|
||||
});
|
||||
},
|
||||
searchChanged(val, ack){
|
||||
this.searchValue = val;
|
||||
setTimeout(ack, 200);
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
spells(){
|
||||
let slotLevel = this.selectedSlot && this.selectedSlot.spellSlotLevelValue || 0;
|
||||
return CreatureProperties.find({
|
||||
let filter = {
|
||||
'ancestors.id': this.creatureId,
|
||||
removed: {$ne: true},
|
||||
inactive: {$ne: true},
|
||||
prepared: true,
|
||||
level: {$lte: slotLevel},
|
||||
}, {
|
||||
};
|
||||
// Apply the filters from the filter menu
|
||||
for (let key in this.booleanFilters){
|
||||
if (this.booleanFilters[key].enabled){
|
||||
let value = this.booleanFilters[key].value;
|
||||
if (key === 'material'){
|
||||
filter[key] = {$exists: this.booleanFilters[key].value};
|
||||
} else {
|
||||
filter[key] = value ? true: {$ne: true};
|
||||
}
|
||||
}
|
||||
}
|
||||
// Apply the search string to the name field
|
||||
if (this.searchValue){
|
||||
filter.name = {
|
||||
$regex: this.searchValue.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'),
|
||||
$options: 'i'
|
||||
};
|
||||
}
|
||||
return CreatureProperties.find(filter, {
|
||||
sort: {order: 1}
|
||||
});
|
||||
},
|
||||
@@ -186,7 +302,7 @@ export default {
|
||||
},
|
||||
selectedSpell(){
|
||||
return CreatureProperties.findOne(this.selectedSpellId);
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -33,6 +33,16 @@
|
||||
>
|
||||
drag_indicator
|
||||
</v-icon>
|
||||
<v-btn
|
||||
v-else-if="showInfoButton"
|
||||
icon
|
||||
flat
|
||||
class="info-icon"
|
||||
:data-id="`spell-info-btn-${model._id}`"
|
||||
@click.stop="$emit('show-info')"
|
||||
>
|
||||
<v-icon>info</v-icon>
|
||||
</v-btn>
|
||||
</v-list-tile-action>
|
||||
</v-list-tile>
|
||||
</template>
|
||||
@@ -46,6 +56,7 @@ export default {
|
||||
props: {
|
||||
preparingSpells: Boolean,
|
||||
hideHandle: Boolean,
|
||||
showInfoButton: Boolean,
|
||||
},
|
||||
computed: {
|
||||
hasClickListener(){
|
||||
@@ -86,4 +97,7 @@ export default {
|
||||
.primary--text .v-icon, .primary--text .v-list__tile__sub-title {
|
||||
color: #b71c1c
|
||||
}
|
||||
.theme--light.info-icon{
|
||||
color: rgba(0,0,0,.54) !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
3
app/imports/ui/utility/escapeRegex.js
Normal file
3
app/imports/ui/utility/escapeRegex.js
Normal file
@@ -0,0 +1,3 @@
|
||||
RegExp.escape = function(s) {
|
||||
return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||
};
|
||||
Reference in New Issue
Block a user