Completed Action form, effects form, reworked form event api
This commit is contained in:
@@ -14,6 +14,13 @@ import updateSchemaMixin from '/imports/api/creature/mixins/updateSchemaMixin.js
|
||||
let Buffs = new Mongo.Collection('buffs');
|
||||
|
||||
let BuffSchema = new SimpleSchema({
|
||||
_id: {
|
||||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Id,
|
||||
autoValue(){
|
||||
if (!this.isSet) return Random.id();
|
||||
}
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
optional: true,
|
||||
@@ -23,9 +30,8 @@ let BuffSchema = new SimpleSchema({
|
||||
optional: true,
|
||||
},
|
||||
duration: {
|
||||
type: SimpleSchema.Integer,
|
||||
type: String,
|
||||
optional: true,
|
||||
min: 0,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -18,6 +18,13 @@ let Effects = new Mongo.Collection('effects');
|
||||
* that modify their final value or presentation in some way
|
||||
*/
|
||||
let EffectSchema = schema({
|
||||
_id: {
|
||||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Id,
|
||||
autoValue(){
|
||||
if (!this.isSet) return Random.id();
|
||||
}
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
optional: true,
|
||||
|
||||
@@ -7,8 +7,7 @@ const AdjustmentSchema = new SimpleSchema({
|
||||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Id,
|
||||
autoValue(){
|
||||
if (this.isSet) return;
|
||||
return Random.id();
|
||||
if (!this.isSet) return Random.id();
|
||||
}
|
||||
},
|
||||
// The roll that determines how much to damage the attribute
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
import ColorPicker from '/imports/ui/components/ColorPicker.Story.vue';
|
||||
import ColumnLayout from "/imports/ui/components/ColumnLayout.Story.vue";
|
||||
import DialogStack from '/imports/ui/dialogStack/DialogStack.Story.vue';
|
||||
import EffectEdit from '/imports/ui/creature/properties/effects/EffectEdit.Story.vue';
|
||||
import EffectForm from '/imports/ui/creature/properties/effects/EffectForm.Story.vue';
|
||||
import EffectEditExpansionList from '/imports/ui/creature/properties/effects/EffectEditExpansionList.Story.vue';
|
||||
import FeatureCard from '/imports/ui/creature/properties/features/FeatureCard.Story.vue';
|
||||
import HealthBar from '/imports/ui/creature/properties/attributes/HealthBar.Story.vue';
|
||||
@@ -66,7 +66,7 @@
|
||||
ColorPicker,
|
||||
ColumnLayout,
|
||||
DialogStack,
|
||||
EffectEdit,
|
||||
EffectForm,
|
||||
EffectEditExpansionList,
|
||||
FeatureCard,
|
||||
HealthBar,
|
||||
|
||||
@@ -2,6 +2,18 @@
|
||||
* Forms that take in a schema and a model of the current data, manages smart
|
||||
* inputs, and sends update events when valid data model changes must occur
|
||||
*/
|
||||
import { get, toPath } from 'lodash';
|
||||
function resolvePath(model, path){
|
||||
let arrayPath = toPath(path);
|
||||
if (arrayPath.length === 1){
|
||||
return { object: model, key: arrayPath[0] };
|
||||
}
|
||||
let objectPath = arrayPath.slice(0, -1);
|
||||
let key = arrayPath.slice(-1);
|
||||
let object = get(model, objectPath);
|
||||
return {object, key};
|
||||
};
|
||||
|
||||
const schemaFormMixin = {
|
||||
data(){ return {
|
||||
valid: true,
|
||||
@@ -26,26 +38,19 @@ const schemaFormMixin = {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
change(modifier, ack){
|
||||
for (let key in modifier){
|
||||
this.$set(this.model, key, modifier[key])
|
||||
}
|
||||
// Sets the value at the given path
|
||||
change({path, value, ack}){
|
||||
let {object, key} = resolvePath(this.model, path);
|
||||
this.$set(object, key, value);
|
||||
if (ack) ack();
|
||||
},
|
||||
push(modifier, ack){
|
||||
for (let key in modifier){
|
||||
this.model[key].push(modifier[key]);
|
||||
}
|
||||
push({path, value, ack}){
|
||||
get(this.model, path).push(value);
|
||||
if (ack) ack();
|
||||
},
|
||||
changeAtIndex(field, index, modifier, ack){
|
||||
for (let key in modifier){
|
||||
this.$set(this.model[field][index], key, modifier[key])
|
||||
}
|
||||
if (ack) ack();
|
||||
},
|
||||
removeAtIndex(field, index, ack){
|
||||
this.model[field].splice(index, 1);
|
||||
pull({path, ack}){
|
||||
let {object, key} = resolvePath(this.model, path);
|
||||
object.splice(key, 1);
|
||||
if (ack) ack();
|
||||
},
|
||||
},
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
@input="input"
|
||||
@focus="focused = true"
|
||||
@blur="focused = false"
|
||||
box
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<text-field
|
||||
label="Name"
|
||||
:value="model.name"
|
||||
@change="(name, ack) => $emit('change', {name}, ack)"
|
||||
@change="(value, ack) => $emit('change', {path: ['name'], value, ack})"
|
||||
:error-messages="errors.name"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
@@ -13,7 +13,7 @@
|
||||
:value="model.type"
|
||||
:error-messages="errors.type"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(type, ack) => $emit('change', {type}, ack)"
|
||||
@change="(value, ack) => $emit('change', {path: ['type'], value, ack})"
|
||||
:hint="actionTypeHints[model.type]"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
@@ -26,7 +26,7 @@
|
||||
:value="model.target"
|
||||
:error-messages="errors.target"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(target, ack) => $emit('change', {target}, ack)"
|
||||
@change="(value, ack) => $emit('change', {path: ['target'], value, ack})"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<div class="layout row wrap">
|
||||
@@ -35,7 +35,7 @@
|
||||
hint="How many times this action can be used before needing to be reset"
|
||||
style="flex-basis: 300px;"
|
||||
:value="model.uses"
|
||||
@change="(uses, ack) => $emit('change', {uses}, ack)"
|
||||
@change="(value, ack) => $emit('change', {path: ['uses'], value, ack})"
|
||||
:error-messages="errors.uses"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
@@ -45,7 +45,7 @@
|
||||
hint="How many times this action has already been used"
|
||||
style="flex-basis: 300px;"
|
||||
:value="model.usesUsed"
|
||||
@change="(uses, ack) => $emit('change', {uses}, ack)"
|
||||
@change="(value, ack) => $emit('change', {path: ['usesUsed'], value, ack})"
|
||||
:error-messages="errors.uses"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
@@ -58,11 +58,11 @@
|
||||
:value="model.reset"
|
||||
:error-messages="errors.reset"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(reset, ack) => $emit('change', {reset}, ack)"
|
||||
@change="(value, ack) => $emit('change', {path: ['reset'], value, ack})"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
</form-section>
|
||||
<form-section name="Adjustments">
|
||||
<form-section name="Damage and Adjustments">
|
||||
<div class="caption">
|
||||
Adjustments can be used to automatically spend resources or deal
|
||||
damage when taking an action.
|
||||
@@ -71,9 +71,22 @@
|
||||
<adjustment-list-form
|
||||
:model="model.adjustments"
|
||||
:parent-target="model.target"
|
||||
@push="(adjustments, ack) => $emit('push', {adjustments}, ack)"
|
||||
@changeAtIndex="(index, modifier, ack) => $emit('changeAtIndex', 'adjustments', index, modifier, ack)"
|
||||
@removeAtIndex="(index, ack) => $emit('removeAtIndex', 'adjustments', index, ack)"
|
||||
@change="({path, value, ack}) => $emit('change', {path: ['adjustments', ...path], value, ack})"
|
||||
@push="({path, value, ack}) => $emit('push', {path: ['adjustments', ...path], value, ack})"
|
||||
@pull="({path, ack}) => $emit('pull', {path: ['adjustments', ...path], ack})"
|
||||
/>
|
||||
</form-section>
|
||||
<form-section name="Buffs">
|
||||
<div class="caption">
|
||||
Buffs apply temporary effects to characters when taking an action.
|
||||
</div>
|
||||
<buff-list-form
|
||||
:model="model.buffs"
|
||||
:parent-target="model.target"
|
||||
:stored="stored"
|
||||
@change="({path, value, ack}) => $emit('change', {path: ['buffs', ...path], value, ack})"
|
||||
@push="({path, value, ack}) => $emit('push', {path: ['buffs', ...path], value, ack})"
|
||||
@pull="({path, ack}) => $emit('pull', {path: ['buffs', ...path], ack})"
|
||||
/>
|
||||
</form-section>
|
||||
</form-sections>
|
||||
@@ -83,14 +96,19 @@
|
||||
<script>
|
||||
import FormSection, {FormSections} from '/imports/ui/components/forms/FormSection.vue';
|
||||
import AdjustmentListForm from '/imports/ui/creature/properties/adjustments/AdjustmentListForm.vue';
|
||||
import BuffListForm from '/imports/ui/creature/properties/buffs/BuffListForm.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FormSection,
|
||||
FormSections,
|
||||
AdjustmentListForm,
|
||||
BuffListForm,
|
||||
},
|
||||
props: {
|
||||
stored: {
|
||||
type: Boolean,
|
||||
},
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
|
||||
@@ -1,43 +1,36 @@
|
||||
<template lang="html">
|
||||
<div class="layout row align-center">
|
||||
<div style="flex-grow: 1;">
|
||||
<div class="layout row wrap">
|
||||
<text-field
|
||||
label="Attribute"
|
||||
hint="The attribute this adjustment will apply to"
|
||||
style="flex-basis: 300px;"
|
||||
:value="model.stat"
|
||||
@change="(stat, ack) => $emit('change', {stat}, ack)"
|
||||
:error-messages="errors.stat"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<text-field
|
||||
label="Damage"
|
||||
hint="The amount of damage to apply to the selected stat, can be a calculation or roll"
|
||||
style="flex-basis: 300px;"
|
||||
:value="model.damage"
|
||||
@change="(damage, ack) => $emit('change', {damage}, ack)"
|
||||
:error-messages="errors.damage"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
</div>
|
||||
<smart-select
|
||||
v-if="parentTarget !== 'self'"
|
||||
label="Target"
|
||||
:hint="targetOptionHint"
|
||||
:items="targetOptions"
|
||||
:value="model.target"
|
||||
:error-messages="errors.target"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(target, ack) => $emit('change', {target}, ack)"
|
||||
<div>
|
||||
<div class="layout row">
|
||||
<text-field
|
||||
label="Attribute"
|
||||
hint="The attribute this adjustment will apply to"
|
||||
style="flex-basis: 300px;"
|
||||
:value="model.stat"
|
||||
@change="(value, ack) => $emit('change', {path: ['stat'], value, ack})"
|
||||
:error-messages="errors.stat"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<text-field
|
||||
label="Damage"
|
||||
hint="The amount of damage to apply to the selected stat, can be a calculation or roll"
|
||||
style="flex-basis: 300px;"
|
||||
:value="model.damage"
|
||||
@change="(value, ack) => $emit('change', {path: ['damage'], value, ack})"
|
||||
:error-messages="errors.damage"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<v-btn outline icon large class="ma-3" @click="$emit('remove')">
|
||||
<v-icon>delete</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<smart-select
|
||||
v-if="parentTarget !== 'self'"
|
||||
label="Target"
|
||||
:hint="targetOptionHint"
|
||||
:items="targetOptions"
|
||||
:value="model.target"
|
||||
:error-messages="errors.target"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(value, ack) => $emit('change', {path: ['target'], value, ack})"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -10,9 +10,13 @@
|
||||
class="mt-4"
|
||||
:model="adjustment"
|
||||
:parent-target="parentTarget"
|
||||
@change="(modifier, ack) => $emit('changeAtIndex', i, modifier, ack)"
|
||||
@remove="(ack) => $emit('removeAtIndex', i, ack)"
|
||||
@change="({path, value, ack}) => $emit('change', {path: [i, ...path], value, ack})"
|
||||
/>
|
||||
<div>
|
||||
<v-btn outline icon large class="ma-3" @click="$emit('pull', {path: [i]})">
|
||||
<v-icon>delete</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</v-slide-x-transition>
|
||||
<div class="layout row justify-end">
|
||||
@@ -46,7 +50,11 @@
|
||||
},
|
||||
addAdjustment(){
|
||||
this.addAdjustmentLoading = true;
|
||||
this.$emit('push', AdjustmentSchema.clean({}), this.acknowledgeAddAdjustment);
|
||||
this.$emit('push', {
|
||||
path: [],
|
||||
value: AdjustmentSchema.clean({}),
|
||||
ack: this.acknowledgeAddAdjustment,
|
||||
});
|
||||
},
|
||||
},
|
||||
props: {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
type="number"
|
||||
class="base-value-field text-xs-center large-format no-flex"
|
||||
:value="model.baseValue"
|
||||
@change="(baseValue, ack) => $emit('change', {baseValue}, ack)"
|
||||
@change="(value, ack) => $emit('change', {path: ['baseValue'], value, ack})"
|
||||
hint="This is the value of the attribute before effects are applied"
|
||||
:error-messages="errors.baseValue"
|
||||
:debounce-time="debounceTime"
|
||||
@@ -16,7 +16,7 @@
|
||||
<text-field
|
||||
label="Name"
|
||||
:value="model.name"
|
||||
@change="(name, ack) => $emit('change', {name}, ack)"
|
||||
@change="(value, ack) => $emit('change', {path: ['name'], value, ack})"
|
||||
:error-messages="errors.name"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
@@ -24,7 +24,7 @@
|
||||
label="Variable name"
|
||||
:value="model.variableName"
|
||||
style="flex-basis: 300px;"
|
||||
@change="(variableName, ack) => $emit('change', {variableName}, ack)"
|
||||
@change="(value, ack) => $emit('change', {path: ['variableName'], value, ack})"
|
||||
hint="Use this name in formulae to reference this attribute"
|
||||
:error-messages="errors.variableName"
|
||||
:debounce-time="debounceTime"
|
||||
@@ -36,7 +36,7 @@
|
||||
:value="model.type"
|
||||
:error-messages="errors.type"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(type, ack) => $emit('change', {type}, ack)"
|
||||
@change="(value, ack) => $emit('change', {path: ['type'], value, ack})"
|
||||
:hint="attributeTypeHints[model.type]"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
@@ -47,7 +47,7 @@
|
||||
class="no-flex"
|
||||
:value="model.decimal"
|
||||
:error-messages="errors.decimal"
|
||||
@change="e => $emit('change', {decimal: !!e})"
|
||||
@change="e => $emit('change', $emit('change', {path: ['decimal'], value: !!e, ack}))"
|
||||
/>
|
||||
<div class="layout row justify-center" style="align-self: stretch;">
|
||||
<text-field
|
||||
@@ -57,7 +57,7 @@
|
||||
style="max-width: 300px;"
|
||||
hint="The attribute's final value is reduced by this amount"
|
||||
:value="model.damage"
|
||||
@change="(damage, ack) => $emit('change', {damage}, ack)"
|
||||
@change="(value, ack) => $emit('change', {path: ['damage'], value, ack})"
|
||||
:error-messages="errors.adjustment"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
@@ -72,7 +72,7 @@
|
||||
:value="model.reset"
|
||||
:error-messages="errors.reset"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(reset, ack) => $emit('change', {reset}, ack)"
|
||||
@change="(value, ack) => $emit('change', {path: ['reset'], value, ack})"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<text-field
|
||||
@@ -81,7 +81,7 @@
|
||||
style="flex-basis: 400px;"
|
||||
:value="model.resetMultiplier"
|
||||
:error-messages="errors.resetMultiplier"
|
||||
@change="(resetMultiplier, ack) => $emit('change', {resetMultiplier}, ack)"
|
||||
@change="(value, ack) => $emit('change', {path: ['resetMultiplier'], value, ack})"
|
||||
hint="Some attributes, like hit dice, only reset by half their total on a long rest"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
|
||||
113
app/imports/ui/creature/properties/buffs/BuffForm.vue
Normal file
113
app/imports/ui/creature/properties/buffs/BuffForm.vue
Normal file
@@ -0,0 +1,113 @@
|
||||
<template lang="html">
|
||||
<div class="buff-form">
|
||||
<text-field
|
||||
label="Name"
|
||||
:value="model.name"
|
||||
@change="(value, ack) => $emit('change', {path: ['name'], value, ack})"
|
||||
:error-messages="errors.name"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<text-area
|
||||
label="Description"
|
||||
:value="model.description"
|
||||
@change="(value, ack) => $emit('change', {path: ['description'], value, ack})"
|
||||
:error-messages="errors.description"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<text-field
|
||||
label="Duration"
|
||||
hint="How long the buff lasts"
|
||||
:value="model.duration"
|
||||
@change="(value, ack) => $emit('change', {path: ['duration'], value, ack})"
|
||||
:error-messages="errors.duration"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<div v-if="stored">
|
||||
<smart-select
|
||||
v-if="parentTarget !== 'self'"
|
||||
label="Target"
|
||||
:hint="targetOptionHint"
|
||||
:items="targetOptions"
|
||||
:value="model.target"
|
||||
:error-messages="errors.target"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(value, ack) => $emit('change', {path: ['target'], value, ack})"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<effect-list-form
|
||||
:model="model.effects"
|
||||
@change="({path, value, ack}) => $emit('change', {path: ['effects', ...path], value, ack})"
|
||||
@push="({path, value, ack}) => $emit('push', {path: ['effects', ...path], value, ack})"
|
||||
@pull="({path, ack}) => $emit('pull', {path: ['effects', ...path], ack})"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EffectListForm from '/imports/ui/creature/properties/effects/EffectListForm.vue';
|
||||
export default {
|
||||
props: {
|
||||
stored: Boolean,
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
errors: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
parentTarget: {
|
||||
type: String,
|
||||
},
|
||||
debounceTime: Number,
|
||||
},
|
||||
components: {
|
||||
EffectListForm,
|
||||
},
|
||||
computed: {
|
||||
targetOptions(){
|
||||
if (this.parentTarget === 'singleTarget') {
|
||||
return [
|
||||
{
|
||||
text: 'Self',
|
||||
value: 'self',
|
||||
}, {
|
||||
text: 'Target',
|
||||
value: 'every',
|
||||
},
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
{
|
||||
text: 'Self',
|
||||
value: 'self',
|
||||
}, {
|
||||
text: 'Roll once for each target',
|
||||
value: 'each',
|
||||
}, {
|
||||
text: 'Roll once and apply to every target',
|
||||
value: 'every',
|
||||
},
|
||||
];
|
||||
}
|
||||
},
|
||||
targetOptionHint(){
|
||||
let hints = {
|
||||
self: 'The buff will be applied to the character taking the action',
|
||||
target: 'The buff will be applied to the target of the action',
|
||||
each: 'The buff will be rolled separately for each of the targets of the action',
|
||||
every: 'The buff will be rolled once and applied to each of the targets of the action',
|
||||
};
|
||||
if (this.parentTarget === 'singleTarget'){
|
||||
hints.each = hints.target;
|
||||
hints.every = hints.target;
|
||||
}
|
||||
return hints[this.model.target];
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
77
app/imports/ui/creature/properties/buffs/BuffListForm.vue
Normal file
77
app/imports/ui/creature/properties/buffs/BuffListForm.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template lang="html">
|
||||
<div>
|
||||
<v-slide-x-transition group>
|
||||
<div
|
||||
v-for="(buff, i) in model"
|
||||
:key="buff._id || i"
|
||||
>
|
||||
<v-divider v-if="i !== 0"/>
|
||||
<div class="layout row align-center">
|
||||
<div style="flex-grow: 1;">
|
||||
<buff-form
|
||||
class="mt-4"
|
||||
:model="buff"
|
||||
:parent-target="parentTarget"
|
||||
:stored="stored"
|
||||
@change="({path, value, ack}) => $emit('change', {path: [i, ...path], value, ack})"
|
||||
@push="({path, value, ack}) => $emit('push', {path: [i, ...path], value, ack})"
|
||||
@pull="({path, ack}) => $emit('pull', {path: [i, ...path], ack})"
|
||||
/>
|
||||
</div>
|
||||
<v-btn outline icon large class="ma-3" @click="$emit('pull', {path: [i]})">
|
||||
<v-icon>delete</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</v-slide-x-transition>
|
||||
<div class="layout row justify-end">
|
||||
<v-btn
|
||||
:loading="addBuffLoading"
|
||||
:disabled="addBuffLoading"
|
||||
outline
|
||||
@click="addBuff"
|
||||
>
|
||||
<v-icon>add</v-icon>
|
||||
Add Buff
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BuffForm from '/imports/ui/creature/properties/buffs/BuffForm.vue';
|
||||
import {StoredBuffSchema, AppliedBuffSchema} from '/imports/api/creature/properties/Buffs.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BuffForm,
|
||||
},
|
||||
props: {
|
||||
stored: Boolean,
|
||||
model: {
|
||||
type: Array,
|
||||
default: () => ([]),
|
||||
},
|
||||
parentTarget: {
|
||||
type: String,
|
||||
},
|
||||
debounceTime: Number,
|
||||
},
|
||||
data(){return {
|
||||
addBuffLoading: false,
|
||||
}},
|
||||
methods: {
|
||||
acknowledgeAddBuff(){
|
||||
this.addBuffLoading = false;
|
||||
},
|
||||
addBuff(){
|
||||
this.addBuffLoading = true;
|
||||
let schema = this.stored ? StoredBuffSchema : AppliedBuffSchema;
|
||||
this.$emit('push', {path: [], value: schema.clean({}), ack: this.acknowledgeAddBuff});
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -14,7 +14,7 @@
|
||||
:class="{'primary--text': expanded === index}"
|
||||
v-bind="effect"
|
||||
/>
|
||||
<effect-edit
|
||||
<effect-form
|
||||
:effect="effect"
|
||||
:stats="stats"
|
||||
@change="({set, ack}) => $emit('change', {set, ack, effectId: effect._id, index})"
|
||||
@@ -24,7 +24,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EffectEdit from '/imports/ui/creature/properties/effects/EffectEdit.vue';
|
||||
import EffectForm from '/imports/ui/creature/properties/effects/EffectForm.vue';
|
||||
import EffectListTile from '/imports/ui/creature/properties/effects/EffectListTile.vue';
|
||||
export default {
|
||||
props: {
|
||||
@@ -32,7 +32,7 @@
|
||||
stats: Array,
|
||||
},
|
||||
components: {
|
||||
EffectEdit,
|
||||
EffectForm,
|
||||
EffectListTile,
|
||||
},
|
||||
data(){ return {
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<v-card-text>
|
||||
<template v-for="(effect, index) in effects">
|
||||
<v-divider v-if="index != 0"/>
|
||||
<effect-edit :key="index" :effect="effect" :stats="stats" @change="e => change(index, e)"/>
|
||||
<effect-form :key="index" :effect="effect" :stats="stats" @change="e => change(index, e)"/>
|
||||
</template>
|
||||
</v-card-text>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EffectEdit from '/imports/ui/creature/properties/effects/EffectEdit.vue';
|
||||
import EffectForm from '/imports/ui/creature/properties/effects/EffectForm.vue';
|
||||
export default {
|
||||
data(){ return {
|
||||
effects: [
|
||||
@@ -34,7 +34,7 @@ export default {
|
||||
],
|
||||
}},
|
||||
components: {
|
||||
EffectEdit,
|
||||
EffectForm,
|
||||
},
|
||||
methods: {
|
||||
change(index, e){
|
||||
@@ -1,57 +1,49 @@
|
||||
<template lang="html">
|
||||
<v-layout row wrap class="effect-edit py-4 px-2">
|
||||
|
||||
<!-- Operation -->
|
||||
<v-flex class="ma-1">
|
||||
<smart-select
|
||||
label="Operation"
|
||||
append-icon="arrow_drop_down"
|
||||
:menu-props="{transition: 'slide-y-transition', lazy: true}"
|
||||
:items="operations"
|
||||
:value="this.effect.operation"
|
||||
@change="(operation, ack) => $emit('change', {set: {operation}, ack})"
|
||||
>
|
||||
<div class="layout row wrap justify-start effect-form">
|
||||
<smart-select
|
||||
label="Operation"
|
||||
append-icon="arrow_drop_down"
|
||||
class="mx-2"
|
||||
:menu-props="{transition: 'slide-y-transition', lazy: true}"
|
||||
:items="operations"
|
||||
:value="model.operation"
|
||||
@change="(value, ack) => $emit('change', {path: ['operation'], value, ack})"
|
||||
>
|
||||
<v-icon
|
||||
class="icon"
|
||||
slot="prepend"
|
||||
:class="iconClass"
|
||||
>{{displayedIcon}}</v-icon>
|
||||
<template slot="item" slot-scope="item">
|
||||
<v-icon
|
||||
class="icon"
|
||||
slot="prepend"
|
||||
:class="iconClass"
|
||||
>{{displayedIcon}}</v-icon>
|
||||
<template slot="item" slot-scope="item">
|
||||
<v-icon
|
||||
class="icon mr-2"
|
||||
>{{getEffectIcon(item.item.value, 1)}}</v-icon>
|
||||
{{item.item.text}}
|
||||
</template>
|
||||
</smart-select>
|
||||
</v-flex>
|
||||
class="icon mr-2"
|
||||
>{{getEffectIcon(item.item.value, 1)}}</v-icon>
|
||||
{{item.item.text}}
|
||||
</template>
|
||||
</smart-select>
|
||||
|
||||
<!-- Value -->
|
||||
<v-flex class="ma-1">
|
||||
<text-field
|
||||
label="Value"
|
||||
:persistent-hint="needsValue"
|
||||
:value="needsValue ? (effect.calculation) : ' '"
|
||||
:disabled="!needsValue"
|
||||
:hint="!isFinite(effect.calculation) && effect.result ? effect.result + '' : '' "
|
||||
@change="(calculation, ack) => $emit('change', {set: {calculation}, ack})"
|
||||
/>
|
||||
</v-flex>
|
||||
<text-field
|
||||
label="Value"
|
||||
class="mr-2"
|
||||
:persistent-hint="needsValue"
|
||||
:value="needsValue ? (model.calculation) : ' '"
|
||||
:disabled="!needsValue"
|
||||
:hint="!isFinite(model.calculation) && model.result ? model.result + '' : '' "
|
||||
@change="(value, ack) => $emit('change', {path: ['calculation'], value, ack})"
|
||||
/>
|
||||
|
||||
<!-- Stat -->
|
||||
<v-flex class="ma-1">
|
||||
<v-autocomplete
|
||||
label="Stat"
|
||||
append-icon="arrow_drop_down"
|
||||
item-text="name"
|
||||
item-value="variableName"
|
||||
:menu-props="{transition: 'slide-y-transition', lazy: true}"
|
||||
:value="effect.stat"
|
||||
:items="stats"
|
||||
@input="stat => $emit('change', {set: {stat}, ack: () => {} })"
|
||||
/>
|
||||
</v-flex>
|
||||
|
||||
</v-layout>
|
||||
<text-field
|
||||
label="Stat"
|
||||
class="mr-2"
|
||||
append-icon="arrow_drop_down"
|
||||
item-text="name"
|
||||
item-value="variableName"
|
||||
:menu-props="{transition: 'slide-y-transition', lazy: true}"
|
||||
:value="model.stat"
|
||||
:items="stats"
|
||||
@change="(value, ack) => $emit('change', {path: ['stat'], value, ack})"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -60,7 +52,7 @@
|
||||
const ICON_SPIN_DURATION = 300;
|
||||
export default {
|
||||
props: {
|
||||
effect: {
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
@@ -86,7 +78,7 @@
|
||||
}},
|
||||
computed: {
|
||||
needsValue(){
|
||||
switch(this.effect.operation) {
|
||||
switch(this.model.operation) {
|
||||
case 'base': return true;
|
||||
case 'add': return true;
|
||||
case 'mul': return true;
|
||||
@@ -104,7 +96,7 @@
|
||||
getEffectIcon,
|
||||
},
|
||||
watch: {
|
||||
'effect.operation': {
|
||||
'model.operation': {
|
||||
immediate: true,
|
||||
handler(newValue, oldValue, e){
|
||||
let newIcon = getEffectIcon(newValue, 1);
|
||||
@@ -149,7 +141,7 @@
|
||||
.hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
.flex {
|
||||
width: 220px;
|
||||
.effect-form > div {
|
||||
flex-basis: 220px;
|
||||
}
|
||||
</style>
|
||||
151
app/imports/ui/creature/properties/effects/EffectListForm.vue
Normal file
151
app/imports/ui/creature/properties/effects/EffectListForm.vue
Normal file
@@ -0,0 +1,151 @@
|
||||
<template lang="html">
|
||||
<div>
|
||||
<v-slide-x-transition group>
|
||||
<div
|
||||
v-for="(effect, i) in model"
|
||||
:key="effect._id || i"
|
||||
>
|
||||
<v-divider v-if="i !== 0"/>
|
||||
<div class="layout row align-center">
|
||||
<div style="flex-grow: 1;">
|
||||
<effect-form
|
||||
class="mt-4"
|
||||
:model="effect"
|
||||
:parent-target="parentTarget"
|
||||
:stored="stored"
|
||||
@change="({path, value, ack}) => $emit('change', {path: [i, ...path], value, ack})"
|
||||
@pull="(ack) => $emit('pull', {path: [i], ack})"
|
||||
/>
|
||||
</div>
|
||||
<v-btn outline icon large class="ma-3" @click="$emit('pull', {path: [i]})">
|
||||
<v-icon>delete</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</v-slide-x-transition>
|
||||
<div class="layout row justify-end">
|
||||
<v-btn
|
||||
:loading="addEffectLoading"
|
||||
:disabled="addEffectLoading"
|
||||
outline
|
||||
@click="addEffect"
|
||||
>
|
||||
<v-icon>add</v-icon>
|
||||
Add Effect
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EffectForm from '/imports/ui/creature/properties/effects/EffectForm.vue';
|
||||
import { EffectSchema } from '/imports/api/creature/properties/Effects.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EffectForm,
|
||||
},
|
||||
props: {
|
||||
stored: Boolean,
|
||||
model: {
|
||||
type: Array,
|
||||
default: () => ([]),
|
||||
},
|
||||
parentTarget: {
|
||||
type: String,
|
||||
},
|
||||
debounceTime: Number,
|
||||
},
|
||||
data(){return {
|
||||
addEffectLoading: false,
|
||||
}},
|
||||
methods: {
|
||||
acknowledgeAddEffect(){
|
||||
this.addEffectLoading = false;
|
||||
},
|
||||
addEffect(){
|
||||
this.addEffectLoading = true;
|
||||
this.$emit('push', {
|
||||
path: [],
|
||||
value: EffectSchema.clean({}),
|
||||
ack: this.acknowledgeAddEffect,
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
<template lang="html">
|
||||
<div>
|
||||
<v-slide-x-transition group>
|
||||
<div
|
||||
v-for="(effect, i) in model"
|
||||
:key="effect._id || i"
|
||||
>
|
||||
<v-divider v-if="i !== 0"/>
|
||||
<div class="layout row align-center">
|
||||
<div style="flex-grow: 1;">
|
||||
<effect-form
|
||||
class="mt-4"
|
||||
:model="effect"
|
||||
@change="({path, value, ack}) => $emit('change', {path: [i, ...path], value, ack})"
|
||||
/>
|
||||
</div>
|
||||
<v-btn outline icon large class="ma-3" @click="$emit('pull', {path: [i]})">
|
||||
<v-icon>delete</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</v-slide-x-transition>
|
||||
<div class="layout row justify-end">
|
||||
<v-btn
|
||||
:loading="addEffectLoading"
|
||||
:disabled="addEffectLoading"
|
||||
outline
|
||||
@click="addEffect"
|
||||
>
|
||||
<v-icon>add</v-icon>
|
||||
Add Effect
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EffectForm from '/imports/ui/creature/properties/effects/EffectForm.vue';
|
||||
import { EffectSchema } from '/imports/api/creature/properties/Effects.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EffectForm,
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Array,
|
||||
default: () => ([]),
|
||||
},
|
||||
debounceTime: Number,
|
||||
},
|
||||
data(){return {
|
||||
addEffectLoading: false,
|
||||
}},
|
||||
methods: {
|
||||
acknowledgeAddEffect(){
|
||||
this.addEffectLoading = false;
|
||||
},
|
||||
addEffect(){
|
||||
this.addEffectLoading = true;
|
||||
this.$emit('push', {
|
||||
path: [],
|
||||
value: EffectSchema.clean({}),
|
||||
ack: this.acknowledgeAddEffect,
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -3,14 +3,14 @@
|
||||
<div slot="toolbar">Add {{propertyName}}</div>
|
||||
<component
|
||||
v-if="type"
|
||||
stored
|
||||
:is="type"
|
||||
class="library-node-form"
|
||||
:model="model"
|
||||
:errors="errors"
|
||||
@change="change"
|
||||
@push="push"
|
||||
@changeAtIndex="changeAtIndex"
|
||||
@removeAtIndex="removeAtIndex"
|
||||
@pull="pull"
|
||||
/>
|
||||
<div
|
||||
slot="actions"
|
||||
|
||||
Reference in New Issue
Block a user