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,
regEx: VARIABLE_NAME_REGEX,
max: STORAGE_LIMITS.variableName,
optional: true,
},
level: {
type: SimpleSchema.Integer,

View File

@@ -1,76 +1,20 @@
import SimpleSchema from 'simpl-schema';
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.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
// lower levels are taken before higher levels
let ClassSchema = createPropertySchema({
name: {
type: String,
optional: true,
max: STORAGE_LIMITS.name,
},
description: {
type: 'inlineCalculationFieldToCompute',
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,
},
});
// Only `classLevel`s with the same variable name can fill the class
variableName: {
type: String,
optional: true,
max: STORAGE_LIMITS.variableName,
},
}).extend(SlotSchema);
const ComputedOnlyClassSchema = createPropertySchema({
description: {
type: 'inlineCalculationFieldToCompute',
optional: true,
},
level: {
type: SimpleSchema.Integer,
optional: true,
@@ -84,7 +28,7 @@ const ComputedOnlyClassSchema = createPropertySchema({
'missingLevels.$': {
type: SimpleSchema.Integer,
},
});
}).extend(ComputedOnlySlotSchema);
const ComputedClassSchema = new SimpleSchema()
.extend(ClassSchema)

View File

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

View File

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

View File

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

View File

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

View File

@@ -14,18 +14,6 @@
/>
</template>
<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
mode="out-in"
>
@@ -39,13 +27,27 @@
@push="push"
@pull="pull"
/>
<component
:is="model.type + 'Viewer'"
<div
v-else-if="!editing && $options.components[model.type + 'Viewer']"
:key="_id"
class="creature-property-viewer"
:model="model"
/>
>
<div
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>
This property can't be viewed yet.
</p>

View File

@@ -36,15 +36,6 @@
@change="({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
label="Tags"
multiple

View File

@@ -1,27 +1,36 @@
<template lang="html">
<div>
<div class="layout">
<computed-field
ref="focusFirst"
label="Damage"
hint="A caculation including dice rolls of the damge to deal to the target when activated by an action"
:model="model.amount"
:error-messages="errors.amount"
@change="({path, value, ack}) =>
$emit('change', {path: ['amount', ...path], value, ack})"
/>
<calculation-error-list :errors="model.amountErrors" />
<smart-select
label="Damage Type"
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)"
/>
</div>
<v-row dense>
<v-col
cols="12"
md="6"
>
<computed-field
ref="focusFirst"
label="Damage"
hint="A caculation including dice rolls of the damge to deal to the target when activated by an action"
:model="model.amount"
:error-messages="errors.amount"
@change="({path, value, ack}) =>
$emit('change', {path: ['amount', ...path], value, ack})"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<smart-select
label="Damage Type"
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
label="Target"
:hint="targetOptionHint"
@@ -71,20 +80,15 @@ 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',
},
];
},
targetOptionHint(){
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',
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'){
hints.each = hints.target;

View File

@@ -49,7 +49,16 @@
:error-messages="errors.stats"
@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
v-else
label="Value"
class="mr-2"
hint="Number or calculation to determine the value of this effect"
@@ -60,15 +69,6 @@
@change="({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
label="Tags"
multiple
@@ -85,13 +85,9 @@
import getEffectIcon from '/imports/ui/utility/getEffectIcon.js';
import propertyFormMixin from '/imports/ui/properties/forms/shared/propertyFormMixin.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;
export default {
components: {
CalculationErrorList,
},
mixins: [propertyFormMixin, attributeListMixin],
data(){ return {
displayedIcon: 'add',
@@ -124,7 +120,6 @@
case 'passiveAdd': return true;
case 'fail': return false;
case 'conditional': return false;
case 'rollBonus': 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 '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 '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 'rollBonus': return 'Add this value to rolls based on this stat';
default: return '';
}
},

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -93,20 +93,10 @@
/>
</div>
</property-field>
</v-row>
<v-row
v-if="model.summary && model.summary.text"
dense
>
<property-description
name="Summary"
:model="model.summary"
/>
</v-row>
<v-row
v-if="model.description && model.description.text"
dense
>
<property-description
name="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">
<div class="class-level-viewer">
<div>
<span class="name text-h5">
{{ model.name }} {{ model.level }}
</span>
</div>
<p class="my-2">
<code>{{ model.variableName }}</code>
</p>
<property-description
:model="model.description"
/>
<v-row
dense
justify="center"
>
<property-field
name="Level"
large
center
:value="model.level"
/>
<property-field
name="Variable Name"
mono
:value="model.variableName"
/>
<property-description
name="Description"
:model="model.description"
/>
</v-row>
</div>
</template>
@@ -19,6 +28,11 @@ import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyV
export default {
mixins: [propertyViewerMixin],
inject: {
context: {
default: {},
},
},
}
</script>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,29 +1,45 @@
<template lang="html">
<div class="buff-viewer">
<property-name :value="model.name" />
<property-field
name="Type"
:value="model.slotType"
/>
<property-field
name="Quantity"
:value="'quantityExpectedResult' in model ? model.quantityExpectedResult : model.quantityExpected"
/>
<property-field
name="Condition"
:value="model.slotCondition"
/>
<property-field
v-if="'slotConditionResult' in model"
name="Condition result"
:value="model.slotConditionResult"
/>
<template v-if="model.tags.length">
<div class="text-caption">
Tags
</div>
<property-tags :tags="model.tags" />
</template>
<div class="slot-viewer">
<v-row dense>
<property-field
name="Variable Name"
mono
:value="model.variableName"
/>
<property-field
name="Condition result"
:value="model.slotCondition && (model.slotCondition.value || model.slotCondition.calculation)"
/>
<property-field
name="Fill with type"
:value="slotTypeName"
/>
<property-field
name="Quantity"
:value="model.quantityExpected && model.quantityExpected.value"
/>
<property-field
name="Unique"
:value="uniqueText"
/>
<property-field
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
:string="model.description"
:calculations="model.descriptionCalculations"
@@ -34,8 +50,24 @@
<script lang="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 {
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>

View File

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

View File

@@ -1,6 +1,8 @@
<template lang="html">
<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"
class="mb-3"
>
@@ -22,16 +24,26 @@
<div
class="layout align-center"
:class="{
'text-body-1': !large,
'text-h4': large,
'justify-center': center,
'mono': mono,
'text-body-1': !isLarge,
'text-h4': isLarge,
'justify-center': isCenter,
'justify-end': end,
'mono': isMono,
}"
style="overflow-x: auto;"
v-bind="$attrs"
>
<slot>
{{ value }}
<template v-if="value !== undefined">
{{ value }}
</template>
<template v-else-if="calculation !== undefined">
{{
calculation.value !== undefined ?
calculation.value :
calculation.calculation
}}
</template>
</slot>
</div>
</div>
@@ -50,7 +62,12 @@ export default {
type: [String, Number, Boolean],
default: undefined,
},
calculation: {
type: Object,
default: undefined,
},
center: Boolean,
end: Boolean,
large: Boolean,
mono: Boolean,
cols: {
@@ -58,6 +75,27 @@ export default {
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>

View File

@@ -1,6 +1,5 @@
import ActionViewer from '/imports/ui/properties/viewers/ActionViewer.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 BuffViewer from '/imports/ui/properties/viewers/BuffViewer.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 {
action: ActionViewer,
adjustment: AdjustmentViewer,
attack: AttackViewer,
attribute: AttributeViewer,
buff: BuffViewer,
container: ContainerViewer,
class: SlotViewer,
classLevel: ClassLevelViewer,
constant: ConstantViewer,
damage: DamageViewer,