Migrating UI for new data structures

This commit is contained in:
Stefan Zermatten
2021-10-15 11:12:40 +02:00
parent f3c52999e8
commit ea68cdf86f
35 changed files with 511 additions and 271 deletions

View File

@@ -1,42 +1,68 @@
<template lang="html">
<div class="action-form">
<div class="layout column align-center">
<icon-picker
label="Icon"
:value="model.icon"
:error-messages="errors.icon"
@change="change('icon', ...arguments)"
/>
</div>
<text-field
ref="focusFirst"
label="Name"
:value="model.name"
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
<smart-select
label="Action type"
:items="actionTypes"
:value="model.actionType"
:error-messages="errors.actionType"
:menu-props="{auto: true, lazy: true}"
:hint="actionTypeHints[model.actionType]"
@change="change('actionType', ...arguments)"
/>
<v-row
justify="center"
class="mb-3"
>
<v-col cols="1">
<icon-color-menu
:model="model"
:errors="errors"
@change="e => $emit('change', e)"
/>
</v-col>
</v-row>
<v-row dense>
<v-col
cols="12"
md="6"
>
<text-field
ref="focusFirst"
label="Name"
:value="model.name"
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<smart-select
label="Action type"
:items="actionTypes"
:value="model.actionType"
:error-messages="errors.actionType"
:menu-props="{auto: true, lazy: true}"
:hint="actionTypeHints[model.actionType]"
@change="change('actionType', ...arguments)"
/>
</v-col>
</v-row>
<computed-field
label="Attack Roll Bonus"
hint="The bonus to attack if this action has an attack roll"
:model="model.rollBonus"
:error-messages="errors.rollBonus"
@change="({path, value, ack}) =>
$emit('change', {path: ['rollBonus', ...path], value, ack})"
/>
<v-slide-x-transition mode="out-in">
<v-switch
v-if="!isAttack"
label="Attack roll"
:value="attackSwitch"
@change="e => attackSwitch = e"
/>
<computed-field
v-else
label="To Hit"
prefix="1d20 + "
hint="The bonus to attack if this action has an attack roll"
:model="model.attackRoll"
:error-messages="errors.attackRoll"
@change="({path, value, ack}) =>
$emit('change', {path: ['attackRoll', ...path], value, ack})"
/>
</v-slide-x-transition>
<inline-computation-field
label="Summary"
hint="This will appear in the action card in the character sheet"
hint="This will appear in the action card in the character sheet, summarise what the action does"
:model="model.summary"
:error-messages="errors.summary"
@change="({path, value, ack}) =>
@@ -45,7 +71,7 @@
<inline-computation-field
label="Description"
hint="The rest of the description that doesn't fit in the summary goes here"
hint="This text will be displayed in the log when the action is taken"
:model="model.description"
:error-messages="errors.description"
@change="({path, value, ack}) =>
@@ -82,25 +108,36 @@
@change="change('target', ...arguments)"
/>
-->
<div class="layout wrap">
<computed-field
label="Uses"
hint="How many times this action can be used before needing to be reset"
:model="model.uses"
:error-messages="errors.uses"
@change="({path, value, ack}) =>
$emit('change', {path: ['uses', ...path], value, ack})"
/>
<text-field
label="Uses used"
type="number"
hint="How many times this action has already been used: should be 0 in most cases"
style="flex-basis: 300px;"
:value="model.usesUsed"
:error-messages="errors.uses"
@change="change('usesUsed', ...arguments)"
/>
</div>
<v-row dense>
<v-col
cols="12"
md="6"
>
<computed-field
label="Uses"
hint="How many times this action can be used before needing to be reset"
class="mr-2"
:model="model.uses"
:error-messages="errors.uses"
@change="({path, value, ack}) =>
$emit('change', {path: ['uses', ...path], value, ack})"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<text-field
label="Uses used"
type="number"
hint="How many times this action has already been used: should be 0 in most cases"
style="flex-basis: 300px;"
:value="model.usesUsed"
:error-messages="errors.uses"
@change="change('usesUsed', ...arguments)"
/>
</v-col>
</v-row>
<smart-select
label="Reset"
clearable
@@ -121,12 +158,14 @@
import FormSection, {FormSections} from '/imports/ui/properties/forms/shared/FormSection.vue';
import ResourcesForm from '/imports/ui/properties/forms/ResourcesForm.vue';
import propertyFormMixin from '/imports/ui/properties/forms/shared/propertyFormMixin.js';
import IconColorMenu from '/imports/ui/properties/forms/shared/IconColorMenu.vue';
export default {
components: {
FormSection,
FormSections,
ResourcesForm,
IconColorMenu,
},
mixins: [propertyFormMixin],
data(){
@@ -176,6 +215,7 @@
value: 'longRest',
}
],
attackSwitch: false,
};
data.actionTypeHints = {};
data.actionTypes.forEach(type => {
@@ -183,6 +223,11 @@
});
return data;
},
computed: {
isAttack(){
return this.attackSwitch || !!this.model.attackRoll?.calculation
}
}
};
</script>

View File

@@ -1,25 +1,35 @@
<template lang="html">
<div class="adjustment-form">
<div class="layout">
<smart-combobox
label="Attribute"
hint="The attribute this adjustment will apply to"
style="flex-basis: 300px;"
:items="attributeList"
:value="model.stat"
:error-messages="errors.stat"
@change="change('stat', ...arguments)"
/>
<computed-field
label="Amount"
hint="The amount of damage to apply to the selected stat, can be a calculation or roll. Negative values will restore the selected from previous damage. If the operation is set, this is the final value of the stat instead."
style="flex-basis: 300px;"
:model="model.amount"
:error-messages="errors.amount"
@change="({path, value, ack}) =>
$emit('change', {path: ['amount', ...path], value, ack})"
/>
</div>
<v-row dense>
<v-col
cols="12"
md="6"
>
<smart-combobox
label="Attribute"
hint="The attribute this adjustment will apply to"
style="flex-basis: 300px;"
:items="attributeList"
:value="model.stat"
:error-messages="errors.stat"
@change="change('stat', ...arguments)"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<computed-field
label="Amount"
:hint="model.operation === 'set' ? setHint : damageHint"
style="flex-basis: 300px;"
:model="model.amount"
:error-messages="errors.amount"
@change="({path, value, ack}) =>
$emit('change', {path: ['amount', ...path], value, ack})"
/>
</v-col>
</v-row>
<smart-select
label="Operation"
class="mx-1"
@@ -69,6 +79,8 @@ export default {
{text: 'Damage', value: 'increment'},
{text: 'Set', value: 'set'},
],
damageHint: 'The amount of damage to apply to the selected stat, can be a calculation or roll. Negative values will restore the selected from previous damage. If the operation is set, this is the final value of the stat instead.',
setHint: 'The value of the stat after applying this adjustment. The stat\'s value can\'t exceed its total',
}},
computed: {
targetOptions(){
@@ -88,11 +100,8 @@ export default {
text: 'Self',
value: 'self',
}, {
text: 'Roll once for each target',
value: 'each',
}, {
text: 'Roll once and apply to every target',
value: 'every',
text: 'Target',
value: 'target',
},
];
}

View File

@@ -13,22 +13,31 @@
$emit('change', {path: ['baseValue', ...path], value, ack})"
/>
</div>
<div class="layout wrap">
<text-field
label="Name"
:value="model.name"
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
<text-field
label="Variable name"
:value="model.variableName"
style="flex-basis: 300px;"
hint="Use this name in calculations to reference this attribute"
:error-messages="errors.variableName"
@change="change('variableName', ...arguments)"
/>
</div>
<v-row dense>
<v-col
cols="12"
md="6"
>
<text-field
label="Name"
:value="model.name"
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<text-field
label="Variable name"
:value="model.variableName"
hint="Use this name in calculations to reference this attribute"
:error-messages="errors.variableName"
@change="change('variableName', ...arguments)"
/>
</v-col>
</v-row>
<smart-select
label="Type"
:items="attributeTypes"

View File

@@ -0,0 +1,68 @@
<template lang="html">
<v-menu offset-y>
<template #activator="{ on, attrs }">
<v-badge
icon="mdi-pencil"
overlap
>
<v-btn
icon
:color="model.color"
outlined
v-bind="attrs"
v-on="on"
>
<property-icon
:model="model"
:color="model.color"
/>
</v-btn>
</v-badge>
</template>
<v-list>
<v-list-item>
<v-list-item-title>
<icon-picker
label="Icon"
:value="model.icon"
:error-messages="errors.icon"
@change="(value, ack) =>$emit('change', {path: ['icon'], value, ack})"
/>
</v-list-item-title>
</v-list-item>
<v-list-item>
<v-list-item-title>
<color-picker
:value="model.color"
@input="value =>$emit('change', {path: ['color'], value})"
/>
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</template>
<script lang="js">
import PropertyIcon from '/imports/ui/properties/shared/PropertyIcon.vue';
import ColorPicker from '/imports/ui/components/ColorPicker.vue';
export default {
components: {
PropertyIcon,
ColorPicker,
},
props: {
model: {
type: Object,
required: true,
},
errors: {
type: Object,
required: true,
},
},
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -4,14 +4,23 @@
*/
import { get, toPath } from 'lodash';
function resolvePath(model, path){
function resolvePath(model, path, set){
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);
let objectPath = arrayPath.slice(0, -1);
let object = model;
// Ensure that nested objects exist before navigating them
objectPath.forEach(pathKey => {
let newObject = object[pathKey];
if (!newObject){
newObject = {};
set(object, pathKey, newObject);
}
object = newObject;
});
return {object, key};
}
@@ -41,7 +50,8 @@ const schemaFormMixin = {
methods: {
// Sets the value at the given path
change({path, value, ack}){
let {object, key} = resolvePath(this.model, path);
let {object, key} = resolvePath(this.model, path, this.$set);
this.$set(object, key, value);
if (ack) ack();
},
@@ -54,7 +64,7 @@ const schemaFormMixin = {
if (ack) ack();
},
pull({path, ack}){
let {object, key} = resolvePath(this.model, path);
let {object, key} = resolvePath(this.model, path, this.$set);
if (!object || !object.splice){
throw `${path.join('.')} is ${object}, doesnt have "splice"`
}