Updated viewers

Action, classlevel, constant, container, damage multiplier, damage, 
effect, feature, folder, item
This commit is contained in:
Stefan Zermatten
2021-10-19 17:19:35 +02:00
parent d6be0ae9f4
commit 1b5bb981e9
31 changed files with 651 additions and 559 deletions

View File

@@ -19,6 +19,7 @@ const ClassLevelSchema = createPropertySchema({
min: 2, min: 2,
regEx: VARIABLE_NAME_REGEX, regEx: VARIABLE_NAME_REGEX,
max: STORAGE_LIMITS.variableName, max: STORAGE_LIMITS.variableName,
optional: true,
}, },
level: { level: {
type: SimpleSchema.Integer, type: SimpleSchema.Integer,

View File

@@ -1,76 +1,20 @@
import SimpleSchema from 'simpl-schema'; import SimpleSchema from 'simpl-schema';
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js'; import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js';
import createPropertySchema from '/imports/api/properties/subSchemas/createPropertySchema.js'; import createPropertySchema from '/imports/api/properties/subSchemas/createPropertySchema.js';
import { SlotSchema, ComputedOnlySlotSchema } from './Slots.js';
// Classes are like slots, except they only take class levels and enforce that // Classes are like slots, except they only take class levels and enforce that
// lower levels are taken before higher levels // lower levels are taken before higher levels
let ClassSchema = createPropertySchema({ let ClassSchema = createPropertySchema({
name: { // Only `classLevel`s with the same variable name can fill the class
type: String, variableName: {
optional: true, type: String,
max: STORAGE_LIMITS.name, optional: true,
}, max: STORAGE_LIMITS.variableName,
description: { },
type: 'inlineCalculationFieldToCompute', }).extend(SlotSchema);
optional: true,
},
// Only `classLevel`s with the same variable name can fill the class
variableName: {
type: String,
optional: true,
max: STORAGE_LIMITS.variableName,
},
classType: {
type: String,
allowedValues: ['startingClass', 'multiClass'],
defaultValue: 'startingClass',
},
// Same tag format as Slots to match library classLevels against
slotTags: {
type: Array,
defaultValue: [],
maxCount: STORAGE_LIMITS.tagCount,
},
'slotTags.$': {
type: String,
max: STORAGE_LIMITS.tagLength,
},
extraTags: {
type: Array,
defaultValue: [],
maxCount: STORAGE_LIMITS.extraTagsCount,
},
'extraTags.$': {
type: Object,
},
'extraTags.$._id': {
type: String,
regEx: SimpleSchema.RegEx.Id,
autoValue(){
if (!this.isSet) return Random.id();
}
},
'extraTags.$.operation': {
type: String,
allowedValues: ['OR', 'NOT'],
defaultValue: 'OR',
},
'extraTags.$.tags': {
type: Array,
defaultValue: [],
maxCount: STORAGE_LIMITS.tagCount,
},
'extraTags.$.tags.$': {
type: String,
max: STORAGE_LIMITS.tagLength,
},
});
const ComputedOnlyClassSchema = createPropertySchema({ const ComputedOnlyClassSchema = createPropertySchema({
description: {
type: 'inlineCalculationFieldToCompute',
optional: true,
},
level: { level: {
type: SimpleSchema.Integer, type: SimpleSchema.Integer,
optional: true, optional: true,
@@ -84,7 +28,7 @@ const ComputedOnlyClassSchema = createPropertySchema({
'missingLevels.$': { 'missingLevels.$': {
type: SimpleSchema.Integer, type: SimpleSchema.Integer,
}, },
}); }).extend(ComputedOnlySlotSchema);
const ComputedClassSchema = new SimpleSchema() const ComputedClassSchema = new SimpleSchema()
.extend(ClassSchema) .extend(ClassSchema)

View File

@@ -14,7 +14,7 @@ const DamageSchema = createPropertySchema({
// Who this damage applies to // Who this damage applies to
target: { target: {
type: String, type: String,
defaultValue: 'every', defaultValue: 'target',
allowedValues: [ allowedValues: [
'self', 'self',
'target', 'target',

View File

@@ -6,6 +6,7 @@ let FeatureSchema = createPropertySchema({
name: { name: {
type: String, type: String,
max: STORAGE_LIMITS.name, max: STORAGE_LIMITS.name,
optional: true,
}, },
summary: { summary: {
type: 'inlineCalculationFieldToCompute', type: 'inlineCalculationFieldToCompute',

View File

@@ -89,7 +89,7 @@ let SlotSchema = createPropertySchema({
const ComputedOnlySlotSchema = createPropertySchema({ const ComputedOnlySlotSchema = createPropertySchema({
// Computed fields // Computed fields
description: { description: {
type: 'inlineCalculationFieldToCompute', type: 'computedOnlyInlineCalculationField',
optional: true, optional: true,
}, },
quantityExpected: { quantityExpected: {

View File

@@ -102,6 +102,7 @@
/> />
</v-slide-y-transition> </v-slide-y-transition>
<v-btn <v-btn
tile
outlined outlined
@click="$emit('toggle-editing')" @click="$emit('toggle-editing')"
> >

View File

@@ -14,18 +14,6 @@
/> />
</template> </template>
<template v-if="model"> <template v-if="model">
<div
v-if="!editing"
class="layout mb-4"
>
<template v-if="!embedded">
<breadcrumbs :model="model" />
</template>
<v-spacer />
<v-chip disabled>
{{ typeName }}
</v-chip>
</div>
<v-fade-transition <v-fade-transition
mode="out-in" mode="out-in"
> >
@@ -39,13 +27,27 @@
@push="push" @push="push"
@pull="pull" @pull="pull"
/> />
<component <div
:is="model.type + 'Viewer'"
v-else-if="!editing && $options.components[model.type + 'Viewer']" v-else-if="!editing && $options.components[model.type + 'Viewer']"
:key="_id" >
class="creature-property-viewer" <div
:model="model" class="layout mb-4"
/> >
<template v-if="!embedded">
<breadcrumbs :model="model" />
</template>
<v-spacer />
<v-chip disabled>
{{ typeName }}
</v-chip>
</div>
<component
:is="model.type + 'Viewer'"
:key="_id"
class="creature-property-viewer"
:model="model"
/>
</div>
<p v-else> <p v-else>
This property can't be viewed yet. This property can't be viewed yet.
</p> </p>

View File

@@ -36,15 +36,6 @@
@change="({path, value, ack}) => @change="({path, value, ack}) =>
$emit('change', {path: ['description', ...path], value, ack})" $emit('change', {path: ['description', ...path], value, ack})"
/> />
<text-field
label="Condition"
hint="A caclulation to determine if this can be added to the character"
placeholder="Always active"
:value="model.slotFillerCondition"
:error-messages="errors.slotFillerCondition"
@change="change('slotFillerCondition', ...arguments)"
/>
<smart-combobox <smart-combobox
label="Tags" label="Tags"
multiple multiple

View File

@@ -1,27 +1,36 @@
<template lang="html"> <template lang="html">
<div> <div>
<div class="layout"> <v-row dense>
<computed-field <v-col
ref="focusFirst" cols="12"
label="Damage" md="6"
hint="A caculation including dice rolls of the damge to deal to the target when activated by an action" >
:model="model.amount" <computed-field
:error-messages="errors.amount" ref="focusFirst"
@change="({path, value, ack}) => label="Damage"
$emit('change', {path: ['amount', ...path], value, ack})" hint="A caculation including dice rolls of the damge to deal to the target when activated by an action"
/> :model="model.amount"
<calculation-error-list :errors="model.amountErrors" /> :error-messages="errors.amount"
<smart-select @change="({path, value, ack}) =>
label="Damage Type" $emit('change', {path: ['amount', ...path], value, ack})"
style="flex-basis: 200px;" />
hint="Use the Healing type to restore hit points" </v-col>
:items="DAMAGE_TYPES" <v-col
:value="model.damageType" cols="12"
:error-messages="errors.damageType" md="6"
:menu-props="{auto: true}" >
@change="change('damageType', ...arguments)" <smart-select
/> label="Damage Type"
</div> style="flex-basis: 200px;"
hint="Use the Healing type to restore hit points"
:items="DAMAGE_TYPES"
:value="model.damageType"
:error-messages="errors.damageType"
:menu-props="{auto: true}"
@change="change('damageType', ...arguments)"
/>
</v-col>
</v-row>
<smart-select <smart-select
label="Target" label="Target"
:hint="targetOptionHint" :hint="targetOptionHint"
@@ -71,20 +80,15 @@ export default {
text: 'Self', text: 'Self',
value: 'self', value: 'self',
}, { }, {
text: 'Roll once for each target', text: 'Target',
value: 'each', value: 'target',
}, {
text: 'Roll once and apply to every target',
value: 'every',
}, },
]; ];
}, },
targetOptionHint(){ targetOptionHint(){
let hints = { let hints = {
self: 'The damage will be applied to the character\'s own attribute when taking the action', self: 'The damage will be applied to the character taking the action',
target: 'The damage will be applied to the target of the action', target: 'The damage will be applied to the target of the action',
each: 'The damage will be rolled separately for each of the targets of the action',
every: 'The damage will be rolled once and applied to each of the targets of the action',
}; };
if (this.parentTarget === 'singleTarget'){ if (this.parentTarget === 'singleTarget'){
hints.each = hints.target; hints.each = hints.target;

View File

@@ -49,7 +49,16 @@
:error-messages="errors.stats" :error-messages="errors.stats"
@change="change('stats', ...arguments)" @change="change('stats', ...arguments)"
/> />
<text-field
v-if="model.operation === 'conditional'"
label="Text"
hint="The text to display on the affected stats"
:value="model.text"
:error-messages="errors.text"
@change="change('text', ...arguments)"
/>
<computed-field <computed-field
v-else
label="Value" label="Value"
class="mr-2" class="mr-2"
hint="Number or calculation to determine the value of this effect" hint="Number or calculation to determine the value of this effect"
@@ -60,15 +69,6 @@
@change="({path, value, ack}) => @change="({path, value, ack}) =>
$emit('change', {path: ['amount', ...path], value, ack})" $emit('change', {path: ['amount', ...path], value, ack})"
/> />
<v-expand-transition>
<text-field
v-if="!isFinite(+model.calculation) && model.result !== undefined"
disabled
label="Result"
:value="model.result"
/>
</v-expand-transition>
<calculation-error-list :errors="model.errors" />
<smart-combobox <smart-combobox
label="Tags" label="Tags"
multiple multiple
@@ -85,13 +85,9 @@
import getEffectIcon from '/imports/ui/utility/getEffectIcon.js'; import getEffectIcon from '/imports/ui/utility/getEffectIcon.js';
import propertyFormMixin from '/imports/ui/properties/forms/shared/propertyFormMixin.js'; import propertyFormMixin from '/imports/ui/properties/forms/shared/propertyFormMixin.js';
import attributeListMixin from '/imports/ui/properties/forms/shared/lists/attributeListMixin.js'; import attributeListMixin from '/imports/ui/properties/forms/shared/lists/attributeListMixin.js';
import CalculationErrorList from '/imports/ui/properties/forms/shared/CalculationErrorList.vue';
const ICON_SPIN_DURATION = 300; const ICON_SPIN_DURATION = 300;
export default { export default {
components: {
CalculationErrorList,
},
mixins: [propertyFormMixin, attributeListMixin], mixins: [propertyFormMixin, attributeListMixin],
data(){ return { data(){ return {
displayedIcon: 'add', displayedIcon: 'add',
@@ -124,7 +120,6 @@
case 'passiveAdd': return true; case 'passiveAdd': return true;
case 'fail': return false; case 'fail': return false;
case 'conditional': return false; case 'conditional': return false;
case 'rollBonus': return true;
default: return true; default: return true;
} }
}, },
@@ -139,9 +134,8 @@
case 'advantage': return 'If this stat is the basis for a check, that check will be at advantage'; case 'advantage': return 'If this stat is the basis for a check, that check will be at advantage';
case 'disadvantage': return 'If this stat is the basis for a check, that check will be at advantage'; case 'disadvantage': return 'If this stat is the basis for a check, that check will be at advantage';
case 'passiveAdd': return 'This value will be added to the passive check'; case 'passiveAdd': return 'This value will be added to the passive check';
case 'fail': return 'Stat based on this attribute will always fail'; case 'fail': return 'Targeted skills and checks will always fail';
case 'conditional': return 'Add a text note to this stat'; case 'conditional': return 'Add a text note to this stat';
case 'rollBonus': return 'Add this value to rolls based on this stat';
default: return ''; default: return '';
} }
}, },

View File

@@ -18,59 +18,79 @@
/> />
</div> </div>
</div> </div>
<div class="layout wrap"> <v-row dense>
<text-field <v-col
ref="focusFirst" cols="12"
label="Name" md="6"
:value="model.name" >
:error-messages="errors.name" <text-field
@change="change('name', ...arguments)" ref="focusFirst"
/> label="Name"
<text-field :value="model.name"
label="Plural name" :error-messages="errors.name"
:value="model.plural" @change="change('name', ...arguments)"
:error-messages="errors.plural" />
hint="The plural name of your item. If your item's name is 'sword' plural name would be 'swords'" </v-col>
@change="change('plural', ...arguments)" <v-col
/> cols="12"
</div> md="6"
<div class="layout wrap"> >
<text-field <text-field
label="Value" label="Plural name"
suffix="gp" :value="model.plural"
type="number" :error-messages="errors.plural"
min="0" hint="The plural name of your item. If your item's name is 'sword' plural name would be 'swords'"
hint="The value of the item in gold pieces, using decimals for values less than 1 gp" @change="change('plural', ...arguments)"
class="mx-1" />
style="flex-basis: 300px;" </v-col>
prepend-inner-icon="$vuetify.icons.two_coins"
:value="model.value" <v-col
:error-messages="errors.value" cols="12"
@change="change('value', ...arguments)" md="6"
/> >
<text-field <text-field
label="Weight" label="Value"
suffix="lb" suffix="gp"
type="number" type="number"
min="0" min="0"
class="mx-1" hint="The value of the item in gold pieces, using decimals for values less than 1 gp"
style="flex-basis: 300px;" prepend-inner-icon="$vuetify.icons.two_coins"
prepend-inner-icon="$vuetify.icons.weight" :value="model.value"
hint="The weight of a single item in lbs. Can be a decimal value" :error-messages="errors.value"
:value="model.weight" @change="change('value', ...arguments)"
:error-messages="errors.weight" />
@change="change('weight', ...arguments)" </v-col>
/> <v-col
</div> cols="12"
<text-field md="6"
label="Quantity" >
type="number" <text-field
min="0" label="Weight"
prepend-inner-icon="$vuetify.icons.abacus" suffix="lb"
:value="model.quantity" type="number"
:error-messages="errors.quantity" min="0"
@change="change('quantity', ...arguments)" prepend-inner-icon="$vuetify.icons.weight"
/> hint="The weight of a single item in lbs. Can be a decimal value"
:value="model.weight"
:error-messages="errors.weight"
@change="change('weight', ...arguments)"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<text-field
label="Quantity"
type="number"
min="0"
prepend-inner-icon="$vuetify.icons.abacus"
:value="model.quantity"
:error-messages="errors.quantity"
@change="change('quantity', ...arguments)"
/>
</v-col>
</v-row>
<inline-computation-field <inline-computation-field
label="Description" label="Description"

View File

@@ -1,6 +1,36 @@
<template lang="html"> <template lang="html">
<div class="slot-form"> <div class="slot-form">
<v-row
v-if="model.type === 'class'"
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"
>
<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>
<text-field <text-field
v-else
ref="focusFirst" ref="focusFirst"
label="Name" label="Name"
:value="model.name" :value="model.name"
@@ -8,6 +38,7 @@
@change="change('name', ...arguments)" @change="change('name', ...arguments)"
/> />
<smart-select <smart-select
v-if="model.type !== 'class'"
label="Type" label="Type"
style="flex-basis: 300px;" style="flex-basis: 300px;"
clearable clearable
@@ -95,6 +126,7 @@
/> />
<smart-select <smart-select
v-if="model.type !== 'class'"
label="Unique" label="Unique"
style="flex-basis: 300px;" style="flex-basis: 300px;"
clearable clearable
@@ -174,6 +206,9 @@
inject: { inject: {
context: { default: {} } context: { default: {} }
}, },
props: {
classForm: Boolean,
},
data(){ data(){
let slotTypes = []; let slotTypes = [];
for (let key in PROPERTIES){ for (let key in PROPERTIES){

View File

@@ -13,7 +13,9 @@
:value="true" :value="true"
:icon="errorIcon(error.type)" :icon="errorIcon(error.type)"
:color="errorColor(error.type)" :color="errorColor(error.type)"
outlined class="mb-2"
dense
text
> >
<pre>{{ error.message }}</pre> <pre>{{ error.message }}</pre>
</v-alert> </v-alert>

View File

@@ -7,16 +7,26 @@
/> />
<template v-for="calc in model.inlineCalculations"> <template v-for="calc in model.inlineCalculations">
<div <div
v-if="calc && calc.calculation && calc.errors.length" v-if="calc && calc.calculation && (
(calc.errors && calc.errors.length) || calc.parseError
)"
:key="calc.calculation" :key="calc.calculation"
class="mb-4"
> >
<v-subheader <div
class="warning--text" class="warning--text mb-2 ml-4"
style="font-family: monospace;" style="font-family: monospace;"
> >
{ {{ calc.calculation }} } { {{ calc.calculation }} }
</v-subheader> </div>
<calculation-error-list :errors="calc.errors" /> <calculation-error-list
v-if="calc.parseError"
:errors="[calc.parseError]"
/>
<calculation-error-list
v-if="calc.errors && calc.errors.length"
:errors="calc.errors"
/>
</div> </div>
</template> </template>
</div> </div>

View File

@@ -33,6 +33,7 @@ export default {
constant: ConstantForm, constant: ConstantForm,
container: ContainerForm, container: ContainerForm,
classLevel: ClassLevelForm, classLevel: ClassLevelForm,
class: SlotForm,
damage: DamageForm, damage: DamageForm,
damageMultiplier: DamageMultiplierForm, damageMultiplier: DamageMultiplierForm,
effect: EffectForm, effect: EffectForm,

View File

@@ -15,6 +15,7 @@
{{ model.damageType }}<span {{ model.damageType }}<span
v-if="model.damageType !== 'healing'" v-if="model.damageType !== 'healing'"
>&nbsp;damage</span> >&nbsp;damage</span>
<span v-if="model.target === 'self'">to self</span>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -93,20 +93,10 @@
/> />
</div> </div>
</property-field> </property-field>
</v-row>
<v-row
v-if="model.summary && model.summary.text"
dense
>
<property-description <property-description
name="Summary" name="Summary"
:model="model.summary" :model="model.summary"
/> />
</v-row>
<v-row
v-if="model.description && model.description.text"
dense
>
<property-description <property-description
name="Description" name="Description"
:model="model.description" :model="model.description"

View File

@@ -1,20 +0,0 @@
<template lang="html">
<action-viewer
:model="model"
attack
/>
</template>
<script lang="js">
import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js';
import ActionViewer from '/imports/ui/properties/viewers/ActionViewer.vue';
export default {
components: {
ActionViewer,
},
mixins: [propertyViewerMixin],
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,16 +1,25 @@
<template lang="html"> <template lang="html">
<div class="class-level-viewer"> <div class="class-level-viewer">
<div> <v-row
<span class="name text-h5"> dense
{{ model.name }} {{ model.level }} justify="center"
</span> >
</div> <property-field
<p class="my-2"> name="Level"
<code>{{ model.variableName }}</code> large
</p> center
<property-description :value="model.level"
:model="model.description" />
/> <property-field
name="Variable Name"
mono
:value="model.variableName"
/>
<property-description
name="Description"
:model="model.description"
/>
</v-row>
</div> </div>
</template> </template>
@@ -19,6 +28,11 @@ import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyV
export default { export default {
mixins: [propertyViewerMixin], mixins: [propertyViewerMixin],
inject: {
context: {
default: {},
},
},
} }
</script> </script>

View File

@@ -1,23 +1,23 @@
<template lang="html"> <template lang="html">
<div class="buff-viewer"> <div class="buff-viewer">
<property-name :value="model.name" /> <v-row dense>
<property-variable-name :value="model.variableName" /> <property-field
<property-field mono
name="Calculation" name="Variable name"
:value="model.calculation" :value="model.variableName"
/> />
<calculation-error-list :errors="model.errors" /> <property-field
name="Calculation"
:value="model.calculation"
/>
</v-row>
</div> </div>
</template> </template>
<script lang="js"> <script lang="js">
import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js' import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js'
import CalculationErrorList from '/imports/ui/properties/forms/shared/CalculationErrorList.vue';
export default { export default {
components: {
CalculationErrorList,
},
mixins: [propertyViewerMixin], mixins: [propertyViewerMixin],
} }
</script> </script>

View File

@@ -1,107 +1,107 @@
<template lang="html"> <template lang="html">
<div class="container-viewer"> <div class="container-viewer">
<property-tags :tags="model.tags" /> <v-row dense>
<div class="layout wrap justify-space-around"> <property-field
<div name="Value"
class="mr-3 my-3" :cols="{cols: 12, md: 6}"
> >
<v-layout <div style="overflow: hidden;">
v-if="model.value !== undefined" <v-layout
align-center v-if="model.value !== undefined"
class="mb-2" align-center
> class="mb-2"
<v-icon
class="mr-2"
x-large
> >
$vuetify.icons.two_coins <v-icon
</v-icon> class="mr-2"
<coin-value large
class="text-h6 mr-2" >
:value="model.value" $vuetify.icons.two_coins
/> </v-icon>
</v-layout> <coin-value
<v-layout class="text-subtitle-1 mr-2"
align-center :value="model.value"
> />
<v-icon </v-layout>
class="mr-2" <v-layout
x-large align-center
> >
$vuetify.icons.cash <v-icon
</v-icon> class="mr-2"
<coin-value large
class="text-h6 mr-2" >
:value="model.contentsValue" $vuetify.icons.cash
/> </v-icon>
<span class="text-h6"> <coin-value
contents class="text-subtitle-1 mr-2"
</span> :value="model.contentsValue"
</v-layout> />
</div> <span class="text-subtitle-1">
<div contents
class="my-3" </span>
</v-layout>
</div>
</property-field>
<property-field
name="Weight"
:cols="{cols: 12, md: 6}"
> >
<v-layout <div style="overflow: hidden;">
v-if="model.weight !== undefined" <v-layout
align-center v-if="model.weight !== undefined"
justify-end align-center
class="mb-2" class="mb-2"
>
<v-icon
class="mr-2"
large
>
$vuetify.icons.weight
</v-icon>
<span class="text-subtitle-1 mr-2">
{{ model.weight }} lb
</span>
</v-layout>
<v-layout
align-center
:class="{'mb-2': model.contentsWeightless}"
>
<v-icon
class="mr-2"
large
>
$vuetify.icons.injustice
</v-icon>
<span class="text-subtitle-1 mr-2">
{{ model.contentsWeight }} lb
</span>
<span
class="text-subtitle-1"
>
contents
</span>
</v-layout>
</div>
</property-field>
<property-field
v-if="model.carried"
value="Carried"
/>
<property-field
v-if="model.contentsWeightless"
>
<v-icon
style="overflow: hidden;"
class="ma-1"
> >
<span class="text-h6 mr-2"> $vuetify.icons.weightless
{{ model.weight }} lb </v-icon>
</span> <span class="ml-1">Contents weightless</span>
<v-icon </property-field>
class="ml-2" <property-description
x-large name="Description"
> :model="model.description"
$vuetify.icons.weight />
</v-icon> </v-row>
</v-layout>
<v-layout
align-center
justify-end
:class="{'mb-2': model.contentsWeightless}"
>
<span class="text-h6 mr-2">
{{ model.contentsWeight }} lb
</span>
<span
class="text-h6"
>
contents
</span>
<v-icon
class="ml-2"
x-large
>
$vuetify.icons.injustice
</v-icon>
</v-layout>
<v-layout
v-if="model.contentsWeightless"
align-center
justify-end
>
<span
class="text-h6"
>
Contents weightless
</span>
<v-icon
class="ml-2"
x-large
>
$vuetify.icons.weightless
</v-icon>
</v-layout>
</div>
</div>
<property-description
:string="model.description"
:calculations="model.descriptionCalculations"
:inactive="model.inactive"
/>
</div> </div>
</template> </template>

View File

@@ -1,9 +1,15 @@
<template lang="html"> <template lang="html">
<div> <div>
<property-name :value="model.name" /> <v-row dense>
<div v-if="model.damageTypes.length"> <property-field
{{ operation }} to {{ model.damageTypes.join(', ') }} damage name="Operation"
</div> :value="operation"
/>
<property-field
name="Damage types"
:value="model.damageTypes.join(', ')"
/>
</v-row>
</div> </div>
</template> </template>

View File

@@ -1,9 +1,22 @@
<template lang="html"> <template lang="html">
<div class="damage-viewer layout align-center"> <div class="damage-viewer">
{{ model.amountResult }} <v-row dense>
{{ model.damageType }}<span <property-field
v-if="model.damageType !== 'healing'" name="Amount"
>&nbsp;damage</span> large
center
:calculation="model.amount"
/>
<property-field
name="Type"
:value="type"
/>
<property-field
v-if="model.target === 'self'"
name="Target"
value="Self"
/>
</v-row>
</div> </div>
</template> </template>
@@ -12,6 +25,12 @@
export default { export default {
mixins: [propertyViewerMixin], mixins: [propertyViewerMixin],
computed: {
type(){
if (this.model.damageType === 'healing') return this.model.damageType;
return `${this.model.damageType} damage`
},
}
} }
</script> </script>

View File

@@ -1,38 +1,37 @@
<template lang="html"> <template lang="html">
<v-list-item class="effect-viewer"> <div class="effect-viewer">
<v-list-item-avatar> <v-row dense>
<v-tooltip bottom> <property-field name="Operation">
<template #activator="{ on }"> <div
class="layout"
style="overflow: hidden;"
>
<v-icon <v-icon
class="mx-2" class="mr-2"
style="cursor: default;"
v-on="on"
> >
{{ effectIcon }} {{ effectIcon }}
</v-icon> </v-icon>
</template> {{ operation }}
<span>{{ operation }}</span> </div>
</v-tooltip> </property-field>
</v-list-item-avatar> <property-field
<v-list-item-action v-if="model.operation !== 'conditional'"
v-if="showValue" name="Amount"
class="text-h5" :value="displayedValue"
> />
{{ displayedValue }} <property-field
</v-list-item-action> name="Stats"
<v-list-item-content> :value="model.stats && model.stats.join(', ')"
<v-list-item-title> mono
{{ model.name }} />
</v-list-item-title> <property-field
<v-list-item-subtitle> v-if="model.operation === 'conditional'"
<code name="Text"
v-for="stat in model.stats" :cols="{cols: 12}"
:key="stat" :value="model.text"
class="mr-1" />
>{{ stat }}</code> </v-row>
</v-list-item-subtitle> </div>
</v-list-item-content>
</v-list-item>
</template> </template>
<script lang="js"> <script lang="js">
@@ -44,7 +43,10 @@
mixins: [propertyViewerMixin], mixins: [propertyViewerMixin],
computed: { computed: {
resolvedValue(){ resolvedValue(){
return this.model.result !== undefined ? this.model.result : this.model.calculation; if (!this.model.amount) return;
return this.model.amount.value !== undefined ?
this.model.amount.value :
this.model.amount.calculation;
}, },
effectIcon(){ effectIcon(){
let value = this.resolvedValue; let value = this.resolvedValue;
@@ -65,21 +67,6 @@
default: return ''; default: return '';
} }
}, },
showValue(){
switch(this.model.operation) {
case 'base': return true;
case 'add': return true;
case 'mul': return true;
case 'min': return true;
case 'max': return true;
case 'advantage': return false;
case 'disadvantage': return false;
case 'passiveAdd': return true;
case 'fail': return false;
case 'conditional': return false;
default: return false;
}
},
displayedValue(){ displayedValue(){
let value = this.resolvedValue; let value = this.resolvedValue;
switch(this.model.operation) { switch(this.model.operation) {

View File

@@ -1,17 +1,15 @@
<template lang="html"> <template lang="html">
<div class="feature-viewer"> <div class="feature-viewer">
<property-name :value="model.name" /> <v-row dense>
<property-description <property-description
:string="model.summary" name="Summary"
:calculations="model.summaryCalculations" :model="model.summary"
:inactive="model.inactive" />
/> <property-description
<v-divider class="mt-3 mb-3" /> name="Description"
<property-description :model="model.description"
:string="model.description" />
:calculations="model.descriptionCalculations" </v-row>
:inactive="model.inactive"
/>
</div> </div>
</template> </template>

View File

@@ -1,7 +1,5 @@
<template lang="html"> <template lang="html">
<div class="folder-viewer"> <div class="folder-viewer" />
<property-name :value="model.name" />
</div>
</template> </template>
<script lang="js"> <script lang="js">

View File

@@ -1,130 +1,147 @@
<template lang="html"> <template lang="html">
<div class="item-viewer"> <div class="item-viewer">
<property-tags :tags="model.tags" /> <v-row dense>
<div <property-field
v-if="model.quantity > 1 || model.showIncrement" v-if="model.quantity > 1 || model.showIncrement"
class="layout justify-center align-center wrap" name="Quantity"
>
<div class="text-h4 mr-3">
{{ model.quantity }}
</div>
<increment-button
v-if="context.creatureId && model.showIncrement"
icon
large large
outlined
color="primary"
:value="model.quantity"
@change="changeQuantity"
> >
<v-icon>$vuetify.icons.abacus</v-icon> <v-spacer />
</increment-button> <div>{{ model.quantity }}</div>
</div> <v-spacer />
<div class="layout wrap justify-space-around"> <increment-button
<div v-if="context.creatureId && model.showIncrement"
icon
large
outlined
color="primary"
:value="model.quantity"
@change="changeQuantity"
>
<v-icon>$vuetify.icons.abacus</v-icon>
</increment-button>
</property-field>
<property-field
v-if="model.value !== undefined" v-if="model.value !== undefined"
class="mr-3 my-3" name="value"
> >
<v-layout <div
v-if="model.quantity > 1" style="overflow: hidden;"
align-center
class="mb-2"
> >
<v-icon <v-layout
class="mr-2"
x-large
>
$vuetify.icons.cash
</v-icon>
<coin-value
class="text-h6"
:value="totalValue"
/>
</v-layout>
<v-layout
align-center
>
<v-icon
class="mr-2"
x-large
>
$vuetify.icons.two_coins
</v-icon>
<coin-value
class="text-h6 mr-2"
:value="model.value"
/>
<span
v-if="model.quantity > 1" v-if="model.quantity > 1"
class="text-h6" align-center
class="mb-2"
> >
each <v-icon
</span> class="mr-2"
</v-layout> large
</div> >
<div $vuetify.icons.cash
</v-icon>
<coin-value
class="text-subtitle-1"
:value="totalValue"
/>
</v-layout>
<v-layout
align-center
>
<v-icon
class="mr-2"
large
>
$vuetify.icons.two_coins
</v-icon>
<coin-value
class="text-subtitle-1 mr-2"
:value="model.value"
/>
<span
v-if="model.quantity > 1"
class="text-subtitle-1"
>
each
</span>
</v-layout>
</div>
</property-field>
<property-field
v-if="model.weight !== undefined" v-if="model.weight !== undefined"
class="my-3" name="Weight"
> >
<v-layout <div
v-if="model.quantity > 1" style="overflow: hidden;"
align-center
justify-end
class="mb-2"
> >
<span class="text-h6"> <v-layout
{{ totalWeight }} lb
</span>
<v-icon
class="ml-2"
x-large
>
$vuetify.icons.injustice
</v-icon>
</v-layout>
<v-layout
align-center
justify-end
:class="{'mb-2': model.attuned}"
>
<span class="text-h6 mr-2">
{{ model.weight }} lb
</span>
<span
v-if="model.quantity > 1" v-if="model.quantity > 1"
class="text-h6" align-center
class="mb-2"
> >
each <v-icon
</span> class="mr-2"
<v-icon large
class="ml-2" >
x-large $vuetify.icons.injustice
</v-icon>
<span class="text-subtitle-1">
{{ totalWeight }} lb
</span>
</v-layout>
<v-layout
align-center
:class="{'mb-2': model.attuned}"
> >
$vuetify.icons.weight <v-icon
</v-icon> class="mr-2"
</v-layout> large
<v-layout >
v-if="model.attuned" $vuetify.icons.weight
align-center </v-icon>
justify-end <span class="text-subtitle-1 mr-2">
{{ model.weight }} lb
</span>
<span
v-if="model.quantity > 1"
class="text-subtitle-1"
>
each
</span>
</v-layout>
</div>
</property-field>
<property-field
v-if="model.equipped"
>
<v-icon
style="overflow: hidden;"
class="ma-1"
> >
<span class="text-h6"> mdi-account-arrow-left
Attuned </v-icon>
</span> <span class="ml-1">Equipped</span>
</property-field>
<property-field
v-if="model.requiresAttunement"
>
<template v-if="model.attuned">
<v-icon <v-icon
class="ml-2" style="overflow: hidden;"
x-large class="ma-1"
> >
$vuetify.icons.spell $vuetify.icons.spell
</v-icon> </v-icon>
</v-layout> <span class="ml-1">Attuned</span>
</div> </template>
</div> <template v-else>
<property-description Requires attunement
:string="model.description" </template>
:calculations="model.descriptionCalculations" </property-field>
:inactive="model.inactive" <property-description
/> name="Description"
:model="model.description"
/>
</v-row>
</div> </div>
</template> </template>
@@ -152,6 +169,13 @@ export default {
totalWeight(){ totalWeight(){
return stripFloatingPointOddities(this.model.weight * this.model.quantity); return stripFloatingPointOddities(this.model.weight * this.model.quantity);
}, },
attunementText(){
if (this.model.requiresAttunement){
if (this.model.attuned) return 'Attuned';
return 'Requires attunement';
}
return undefined;
}
}, },
methods: { methods: {
getIcon(name){ getIcon(name){

View File

@@ -1,29 +1,45 @@
<template lang="html"> <template lang="html">
<div class="buff-viewer"> <div class="slot-viewer">
<property-name :value="model.name" /> <v-row dense>
<property-field <property-field
name="Type" name="Variable Name"
:value="model.slotType" mono
/> :value="model.variableName"
<property-field />
name="Quantity" <property-field
:value="'quantityExpectedResult' in model ? model.quantityExpectedResult : model.quantityExpected" name="Condition result"
/> :value="model.slotCondition && (model.slotCondition.value || model.slotCondition.calculation)"
<property-field />
name="Condition" <property-field
:value="model.slotCondition" name="Fill with type"
/> :value="slotTypeName"
<property-field />
v-if="'slotConditionResult' in model" <property-field
name="Condition result" name="Quantity"
:value="model.slotConditionResult" :value="model.quantityExpected && model.quantityExpected.value"
/> />
<template v-if="model.tags.length"> <property-field
<div class="text-caption"> name="Unique"
Tags :value="uniqueText"
</div> />
<property-tags :tags="model.tags" /> <property-field
</template> name="Tags Required"
:cols="{cols: 12}"
>
<div>
<property-tags :tags="model.slotTags" />
<div
v-for="tags in model.extraTags"
:key="tags._id"
>
<div class="text-caption">
{{ tags.operation }}
</div>
<property-tags :tags="tags.tags" />
</div>
</div>
</property-field>
</v-row>
<property-description <property-description
:string="model.description" :string="model.description"
:calculations="model.descriptionCalculations" :calculations="model.descriptionCalculations"
@@ -34,8 +50,24 @@
<script lang="js"> <script lang="js">
import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js' import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js'
import {getPropertyName} from '/imports/constants/PROPERTIES.js';
const uniqueText = {
uniqueInSlot: 'Each property inside this slot should be unique',
uniqueInCreature: 'Properties in this slot should be unique across the whole character',
}
export default { export default {
mixins: [propertyViewerMixin], mixins: [propertyViewerMixin],
computed: {
slotTypeName(){
if (!this.model.slotType) return;
return getPropertyName(this.model.slotType);
},
uniqueText(){
if (!this.model.unique) return;
return uniqueText[this.model.unique]
},
}
} }
</script> </script>

View File

@@ -2,7 +2,7 @@
<property-field <property-field
v-if="model && (model.value || model.text)" v-if="model && (model.value || model.text)"
:name="name" :name="name"
:cols="{col: 12}" :cols="{cols: 12}"
> >
<markdown-text <markdown-text
:markdown="model.value || model.text" :markdown="model.value || model.text"

View File

@@ -1,6 +1,8 @@
<template lang="html"> <template lang="html">
<v-col <v-col
v-if="value !== undefined || ($slots.default && $slots.default.length)" v-if="value !== undefined ||
calculation !== undefined ||
($slots.default && $slots.default.length)"
v-bind="cols" v-bind="cols"
class="mb-3" class="mb-3"
> >
@@ -22,16 +24,26 @@
<div <div
class="layout align-center" class="layout align-center"
:class="{ :class="{
'text-body-1': !large, 'text-body-1': !isLarge,
'text-h4': large, 'text-h4': isLarge,
'justify-center': center, 'justify-center': isCenter,
'mono': mono, 'justify-end': end,
'mono': isMono,
}" }"
style="overflow-x: auto;" style="overflow-x: auto;"
v-bind="$attrs" v-bind="$attrs"
> >
<slot> <slot>
{{ value }} <template v-if="value !== undefined">
{{ value }}
</template>
<template v-else-if="calculation !== undefined">
{{
calculation.value !== undefined ?
calculation.value :
calculation.calculation
}}
</template>
</slot> </slot>
</div> </div>
</div> </div>
@@ -50,7 +62,12 @@ export default {
type: [String, Number, Boolean], type: [String, Number, Boolean],
default: undefined, default: undefined,
}, },
calculation: {
type: Object,
default: undefined,
},
center: Boolean, center: Boolean,
end: Boolean,
large: Boolean, large: Boolean,
mono: Boolean, mono: Boolean,
cols: { cols: {
@@ -58,6 +75,27 @@ export default {
default: () => ({cols: 12, sm: 6, md: 4}), default: () => ({cols: 12, sm: 6, md: 4}),
}, },
}, },
computed: {
showCalculationInsteadOfValue(){
if (!this.calculation) return;
return this.calculation && this.calculation.value === undefined;
},
// large and center are only applied to calculations if we are showing their
// value, if we are showing the calculation itself, large and center are
// turned off
isLarge(){
if (this.showCalculationInsteadOfValue) return false;
return this.large;
},
isCenter(){
if (this.showCalculationInsteadOfValue) return false;
return this.center;
},
isMono(){
if (this.showCalculationInsteadOfValue) return true;
return this.mono;
}
},
} }
</script> </script>

View File

@@ -1,6 +1,5 @@
import ActionViewer from '/imports/ui/properties/viewers/ActionViewer.vue'; import ActionViewer from '/imports/ui/properties/viewers/ActionViewer.vue';
import AdjustmentViewer from '/imports/ui/properties/viewers/AdjustmentViewer.vue'; import AdjustmentViewer from '/imports/ui/properties/viewers/AdjustmentViewer.vue';
import AttackViewer from '/imports/ui/properties/viewers/AttackViewer.vue';
import AttributeViewer from '/imports/ui/properties/viewers/AttributeViewer.vue'; import AttributeViewer from '/imports/ui/properties/viewers/AttributeViewer.vue';
import BuffViewer from '/imports/ui/properties/viewers/BuffViewer.vue'; import BuffViewer from '/imports/ui/properties/viewers/BuffViewer.vue';
import ContainerViewer from '/imports/ui/properties/viewers/ContainerViewer.vue'; import ContainerViewer from '/imports/ui/properties/viewers/ContainerViewer.vue';
@@ -27,10 +26,10 @@ import ToggleViewer from '/imports/ui/properties/viewers/ToggleViewer.vue';
export default { export default {
action: ActionViewer, action: ActionViewer,
adjustment: AdjustmentViewer, adjustment: AdjustmentViewer,
attack: AttackViewer,
attribute: AttributeViewer, attribute: AttributeViewer,
buff: BuffViewer, buff: BuffViewer,
container: ContainerViewer, container: ContainerViewer,
class: SlotViewer,
classLevel: ClassLevelViewer, classLevel: ClassLevelViewer,
constant: ConstantViewer, constant: ConstantViewer,
damage: DamageViewer, damage: DamageViewer,