UI work to improve look and feel of Viewers
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import _variable from './computeByType/computeVariable.js';
|
||||
import action from './computeByType/computeAction.js';
|
||||
import attribute from './computeByType/computeAttribute.js';
|
||||
import skill from './computeByType/computeSkill.js';
|
||||
import slot from './computeByType/computeSlot.js';
|
||||
import container from './computeByType/computeContainer.js';
|
||||
|
||||
@@ -9,6 +10,7 @@ export default Object.freeze({
|
||||
action,
|
||||
attribute,
|
||||
container,
|
||||
skill,
|
||||
slot,
|
||||
spell: action,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// If we compute this skill without a variable name, it just
|
||||
// uses its base value, proficiency, and damage since no effects can target it
|
||||
// If this skill does have a variable name, it is recomputed later
|
||||
// by computeVariableAsSkill
|
||||
export default function computeSkill(computation, node){
|
||||
const prop = node.data;
|
||||
prop.proficiency = prop.baseProficiency;
|
||||
let profBonus = computation.scope['proficiencyBonus']?.value || 0;
|
||||
// Multiply the proficiency bonus by the actual proficiency
|
||||
if(prop.proficiency === 0.49){
|
||||
// Round down proficiency bonus in the special case
|
||||
profBonus = Math.floor(profBonus * 0.5);
|
||||
} else {
|
||||
profBonus = Math.ceil(profBonus * prop.proficiency);
|
||||
}
|
||||
|
||||
const ability = computation.scope[prop.ability];
|
||||
prop.abilityMod = ability?.modifier || 0;
|
||||
|
||||
const base = prop.baseValue?.value || 0;
|
||||
|
||||
let result = base + prop.abilityMod + profBonus;
|
||||
if (Number.isFinite(result)){
|
||||
result = Math.floor(result);
|
||||
}
|
||||
|
||||
prop.value = result;
|
||||
}
|
||||
@@ -15,6 +15,7 @@ export default function(){
|
||||
assert.equal(scope('strength').modifier, 1);
|
||||
assert.equal(prop('referencesDexId').value, 4);
|
||||
assert.equal(prop('hitDiceId').constitutionMod, 5);
|
||||
assert.equal(prop('overriddenDexId').overridden, true, 'override properties with the same variable name');
|
||||
assert.equal(
|
||||
prop('parseErrorId').baseValue.value, null,
|
||||
'Parse errors should null the value'
|
||||
@@ -44,11 +45,22 @@ var testProperties = [
|
||||
calculation: '12'
|
||||
},
|
||||
}),
|
||||
clean({
|
||||
_id: 'overriddenDexId',
|
||||
variableName: 'dexterity',
|
||||
type: 'attribute',
|
||||
attributeType: 'ability',
|
||||
order: 1,
|
||||
baseValue: {
|
||||
calculation: '15'
|
||||
},
|
||||
}),
|
||||
clean({
|
||||
_id: 'dexterityId',
|
||||
variableName: 'dexterity',
|
||||
type: 'attribute',
|
||||
attributeType: 'ability',
|
||||
order: 2,
|
||||
baseValue: {
|
||||
calculation: '15'
|
||||
},
|
||||
|
||||
@@ -20,6 +20,7 @@ let SkillSchema = createPropertySchema({
|
||||
regEx: VARIABLE_NAME_REGEX,
|
||||
min: 2,
|
||||
max: STORAGE_LIMITS.variableName,
|
||||
optional: true,
|
||||
},
|
||||
// The variable name of the ability this skill relies on
|
||||
ability: {
|
||||
|
||||
@@ -11,7 +11,7 @@ const unaryOperator = {
|
||||
},
|
||||
resolve(fn, node, scope, context){
|
||||
const {result: rightNode} = resolve(fn, node.right, scope, context);
|
||||
if (rightNode.parseType !== 'number'){
|
||||
if (rightNode.valueType !== 'number'){
|
||||
return {
|
||||
result: unaryOperator.create({
|
||||
operator: node.operator,
|
||||
|
||||
@@ -39,13 +39,15 @@
|
||||
},
|
||||
meteor: {
|
||||
children(){
|
||||
return nodesToTree({
|
||||
const children = nodesToTree({
|
||||
collection: CreatureProperties,
|
||||
ancestorId: this.root.id,
|
||||
filter: this.filter,
|
||||
includeFilteredDocAncestors: true,
|
||||
includeFilteredDocDescendants: true,
|
||||
});
|
||||
this.$emit('length', children.length);
|
||||
return children;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -41,28 +41,34 @@
|
||||
This property can't be viewed yet.
|
||||
</p>
|
||||
</v-fade-transition>
|
||||
<template v-if="!editing && !embedded">
|
||||
<v-divider class="my-2" />
|
||||
<property-field
|
||||
v-if="!editing && !embedded && childrenLength"
|
||||
name="Child properties"
|
||||
:cols="{cols: 12}"
|
||||
>
|
||||
<creature-properties-tree
|
||||
v-if="!editing"
|
||||
style="width: 100%;"
|
||||
:root="{collection: 'creatureProperties', id: model._id}"
|
||||
@length="childrenLength = $event"
|
||||
@selected="selectSubProperty"
|
||||
/>
|
||||
<v-btn
|
||||
text
|
||||
data-id="insert-creature-property-btn"
|
||||
@click="addProperty"
|
||||
>
|
||||
<v-icon>mdi-plus</v-icon>
|
||||
Property
|
||||
</v-btn>
|
||||
</template>
|
||||
</property-field>
|
||||
</template>
|
||||
<div
|
||||
v-if="!embedded"
|
||||
slot="actions"
|
||||
class="layout justify-end"
|
||||
class="layout"
|
||||
>
|
||||
<v-btn
|
||||
v-if="!editing && !embedded"
|
||||
text
|
||||
data-id="insert-creature-property-btn"
|
||||
@click="addProperty"
|
||||
>
|
||||
<v-icon>mdi-plus</v-icon>
|
||||
Property
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
text
|
||||
@click="$store.dispatch('popDialogStack')"
|
||||
@@ -99,6 +105,7 @@ import { getHighestOrder } from '/imports/api/parenting/order.js';
|
||||
import insertProperty from '/imports/api/creature/creatureProperties/methods/insertProperty.js';
|
||||
import Breadcrumbs from '/imports/ui/creature/creatureProperties/Breadcrumbs.vue';
|
||||
import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js';
|
||||
import PropertyField from '/imports/ui/properties/viewers/shared/PropertyField.vue';
|
||||
|
||||
let formIndex = {};
|
||||
for (let key in propertyFormIndex){
|
||||
@@ -119,6 +126,7 @@ export default {
|
||||
PropertyToolbar,
|
||||
CreaturePropertiesTree,
|
||||
Breadcrumbs,
|
||||
PropertyField,
|
||||
},
|
||||
props: {
|
||||
_id: String,
|
||||
@@ -130,6 +138,7 @@ export default {
|
||||
// CurrentId lags behind Id by one tick so that events fired by destroying
|
||||
// forms keyed to the old ID are applied before the new ID overwrites it
|
||||
currentId: undefined,
|
||||
childrenLength: 0,
|
||||
}},
|
||||
meteor: {
|
||||
model(){
|
||||
|
||||
@@ -70,8 +70,8 @@
|
||||
/>
|
||||
</template>
|
||||
<template v-if="model.summary">
|
||||
<property-description
|
||||
:model="model.summary"
|
||||
<markdown-text
|
||||
:markdown="model.summary.value || model.summary.text"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
@@ -84,14 +84,14 @@ import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
import doAction from '/imports/api/engine/actions/doAction.js';
|
||||
import AttributeConsumedView from '/imports/ui/properties/components/actions/AttributeConsumedView.vue';
|
||||
import ItemConsumedView from '/imports/ui/properties/components/actions/ItemConsumedView.vue';
|
||||
import PropertyDescription from '/imports/ui/properties/viewers/shared/PropertyDescription.vue';
|
||||
import PropertyIcon from '/imports/ui/properties/shared/PropertyIcon.vue';
|
||||
import MarkdownText from '/imports/ui/components/MarkdownText.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AttributeConsumedView,
|
||||
ItemConsumedView,
|
||||
PropertyDescription,
|
||||
MarkdownText,
|
||||
PropertyIcon,
|
||||
},
|
||||
inject: {
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
@click="click"
|
||||
>
|
||||
<div class="layout align-center">
|
||||
<v-card-title class="value text-h4">
|
||||
<v-card-title class="value text-h4 flex-shrink-0">
|
||||
{{ computedValue }}
|
||||
</v-card-title>
|
||||
<v-card-title class="name text-subtitle-1 text-truncate pl-0">
|
||||
<v-card-title class="name text-subtitle-1 text-truncate d-block pl-0">
|
||||
{{ model.name }}
|
||||
</v-card-title>
|
||||
</div>
|
||||
@@ -28,14 +28,10 @@
|
||||
return this.$listeners && !!this.$listeners.click
|
||||
},
|
||||
computedValue(){
|
||||
if (this.model.type === 'attribute'){
|
||||
if (this.model.attributeType === 'modifier'){
|
||||
return numberToSignedString(this.model.value);
|
||||
} else {
|
||||
return this.model.value
|
||||
}
|
||||
if (this.model.attributeType === 'modifier' || this.model.type === 'skill'){
|
||||
return numberToSignedString(this.model.value);
|
||||
} else {
|
||||
return this.model.value;
|
||||
return this.model.value
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
<template lang="html">
|
||||
<div class="attribute-viewer">
|
||||
<v-layout
|
||||
column
|
||||
align-center
|
||||
<v-row
|
||||
dense
|
||||
align="stretch"
|
||||
justify="center"
|
||||
justify-sm="start"
|
||||
>
|
||||
<v-layout v-if="model.value !== undefined">
|
||||
<property-field
|
||||
:name="model.damage !== undefined ? 'Value / Total': 'Value'"
|
||||
center
|
||||
>
|
||||
<v-spacer />
|
||||
<div
|
||||
class="text-h4 mr-3"
|
||||
>
|
||||
@@ -17,93 +23,171 @@
|
||||
{{ model.value }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<v-spacer />
|
||||
<increment-button
|
||||
v-if="context.creatureId"
|
||||
icon
|
||||
large
|
||||
outlined
|
||||
icon
|
||||
tile
|
||||
color="primary"
|
||||
:value="model.value"
|
||||
@change="damageProperty"
|
||||
>
|
||||
<v-icon>$vuetify.icons.abacus</v-icon>
|
||||
<v-icon>
|
||||
$vuetify.icons.abacus
|
||||
</v-icon>
|
||||
</increment-button>
|
||||
</v-layout>
|
||||
<div
|
||||
</property-field>
|
||||
<property-field
|
||||
v-if="model.modifier !== undefined"
|
||||
class="text-h6"
|
||||
name="Modifier"
|
||||
center
|
||||
:value="isFinite(model.modifier) ?
|
||||
numberToSignedString(model.modifier) :
|
||||
model.modifier"
|
||||
>
|
||||
{{ numberToSignedString(model.modifier) }}
|
||||
</div>
|
||||
</v-layout>
|
||||
<div>
|
||||
<property-name :value="model.name" />
|
||||
<property-variable-name :value="model.variableName" />
|
||||
</div>
|
||||
<property-field
|
||||
v-if="model.attributeType === 'hitDice' && model.hitDiceSize"
|
||||
name="Hit dice size"
|
||||
:value="model.hitDiceSize"
|
||||
/>
|
||||
<property-field
|
||||
v-if="reset && model.attributeType !== 'hitDice'"
|
||||
name="Reset"
|
||||
:value="reset"
|
||||
/>
|
||||
<property-description
|
||||
:model="model.description"
|
||||
/>
|
||||
<v-list>
|
||||
<attribute-effect
|
||||
v-for="effect in baseEffects"
|
||||
:key="effect._id"
|
||||
:model="effect"
|
||||
:hide-breadcrumbs="effect._id === model._id"
|
||||
:data-id="effect._id"
|
||||
@click="effect._id !== model._id && clickEffect(effect._id)"
|
||||
<div class="text-h6">
|
||||
{{ numberToSignedString(model.modifier) }}
|
||||
</div>
|
||||
</property-field>
|
||||
<property-field
|
||||
name="Variable Name"
|
||||
:value="model.variableName"
|
||||
/>
|
||||
<attribute-effect
|
||||
v-for="effect in effects"
|
||||
:key="effect._id"
|
||||
:model="effect"
|
||||
:data-id="effect._id"
|
||||
@click="clickEffect(effect._id)"
|
||||
<property-field
|
||||
name="Type"
|
||||
:value="attributeTypes[model.attributeType]"
|
||||
/>
|
||||
</v-list>
|
||||
<property-field
|
||||
v-if="model.attributeType === 'hitDice' && model.hitDiceSize"
|
||||
name="Hit dice size"
|
||||
:value="model.hitDiceSize"
|
||||
/>
|
||||
<property-field
|
||||
v-if="model.attributeType === 'hitDice'"
|
||||
name="Constitution modifier"
|
||||
:value="isFinite(model.constitutionMod) ?
|
||||
numberToSignedString(model.constitutionMod) :
|
||||
model.constitutionMod"
|
||||
/>
|
||||
<property-field
|
||||
v-if="model.attributeType === 'spellSlot' && model.spellSlotLevel"
|
||||
name="Spell slot level"
|
||||
:value="model.spellSlotLevel.value !== undefined ? model.spellSlotLevel.value : model.spellSlotLevel.calculation"
|
||||
/>
|
||||
<property-field
|
||||
v-if="model.attributeType === 'ability' && model.proficiency !== undefined"
|
||||
name="Proficiency"
|
||||
>
|
||||
<v-icon
|
||||
style="height: 12px"
|
||||
class="ml-1 mr-2"
|
||||
>
|
||||
{{ proficiencyIcon }}
|
||||
</v-icon>
|
||||
<div>
|
||||
{{ proficiencyText[model.proficiency] }}
|
||||
</div>
|
||||
</property-field>
|
||||
<property-field
|
||||
v-if="reset && model.attributeType !== 'hitDice'"
|
||||
name="Reset"
|
||||
:value="reset"
|
||||
/>
|
||||
<property-field
|
||||
v-if="model.overridden"
|
||||
:cols="{cols: 6, md: 12}"
|
||||
name="Overridden"
|
||||
value="Overriden by another property with the same variable name"
|
||||
/>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<property-description
|
||||
label="Description"
|
||||
:model="model.description"
|
||||
/>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<property-field
|
||||
v-if="baseEffects.length || effects.length"
|
||||
:cols="{col: 12}"
|
||||
name="Effects"
|
||||
>
|
||||
<v-list>
|
||||
<attribute-effect
|
||||
v-for="effect in baseEffects"
|
||||
:key="effect._id"
|
||||
:model="effect"
|
||||
:hide-breadcrumbs="effect._id === model._id"
|
||||
:data-id="effect._id"
|
||||
@click="effect._id !== model._id && clickEffect(effect._id)"
|
||||
/>
|
||||
<attribute-effect
|
||||
v-for="effect in effects"
|
||||
:key="effect._id"
|
||||
:model="effect"
|
||||
:data-id="effect._id"
|
||||
@click="clickEffect(effect._id)"
|
||||
/>
|
||||
</v-list>
|
||||
</property-field>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js'
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
import AttributeEffect from '/imports/ui/properties/components/attributes/AttributeEffect.vue';
|
||||
import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js'
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
import AttributeEffect from '/imports/ui/properties/components/attributes/AttributeEffect.vue';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import damageProperty from '/imports/api/creature/creatureProperties/methods/damageProperty.js';
|
||||
import IncrementButton from '/imports/ui/components/IncrementButton.vue';
|
||||
import getProficiencyIcon from '/imports/ui/utility/getProficiencyIcon.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AttributeEffect,
|
||||
export default {
|
||||
components: {
|
||||
AttributeEffect,
|
||||
IncrementButton,
|
||||
},
|
||||
mixins: [propertyViewerMixin],
|
||||
},
|
||||
mixins: [propertyViewerMixin],
|
||||
inject: {
|
||||
context: { default: {} }
|
||||
},
|
||||
computed: {
|
||||
reset(){
|
||||
let reset = this.model.reset
|
||||
if (reset === 'shortRest'){
|
||||
return 'Reset on a short rest';
|
||||
} else if (reset === 'longRest'){
|
||||
return 'Reset on a long rest';
|
||||
}
|
||||
data(){return {
|
||||
attributeTypes: {
|
||||
ability: 'Ability score',
|
||||
stat: 'Stat',
|
||||
modifier: 'Modifier',
|
||||
hitDice: 'Hit dice',
|
||||
healthBar: 'Health bar',
|
||||
resource: 'Resource',
|
||||
spellSlot: 'Spell slot',
|
||||
utility: 'Utility',
|
||||
},
|
||||
proficiencyText: {
|
||||
0: 'Not proficient',
|
||||
1: 'Proficient',
|
||||
0.49: 'Half proficiency bonus rounded down',
|
||||
0.5: 'Half proficiency bonus rounded up',
|
||||
2: 'Double proficiency bonus',
|
||||
},
|
||||
}},
|
||||
computed: {
|
||||
reset(){
|
||||
let reset = this.model.reset
|
||||
if (reset === 'shortRest'){
|
||||
return 'Reset on a short rest';
|
||||
} else if (reset === 'longRest'){
|
||||
return 'Reset on a long rest';
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
numberToSignedString,
|
||||
},
|
||||
proficiencyIcon(){
|
||||
return getProficiencyIcon(this.model.proficiency);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
numberToSignedString,
|
||||
clickEffect(id){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
@@ -118,7 +202,7 @@
|
||||
value: value
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
baseEffects(){
|
||||
if (this.context.creatureId && this.model.variableName){
|
||||
@@ -155,20 +239,20 @@
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.ability-value {
|
||||
font-weight: 600;
|
||||
font-size: 24px !important;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
.mod, .ability-value {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
.attribute-value {
|
||||
text-align: center;
|
||||
}
|
||||
.ability-value {
|
||||
font-weight: 600;
|
||||
font-size: 24px !important;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
.mod, .ability-value {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
.attribute-value {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,84 +1,114 @@
|
||||
<template lang="html">
|
||||
<div class="skill-viewer">
|
||||
<v-layout
|
||||
column
|
||||
align-center
|
||||
<v-row
|
||||
dense
|
||||
justify="center"
|
||||
justify-sm="start"
|
||||
>
|
||||
<div
|
||||
<property-field
|
||||
v-if="model.value !== undefined"
|
||||
class="text-h4 layout align-center"
|
||||
center
|
||||
large
|
||||
name="Roll bonus"
|
||||
:value="isFinite(model.value) ?
|
||||
numberToSignedString(model.value) :
|
||||
model.value"
|
||||
/>
|
||||
<property-field
|
||||
v-if="model.proficiency !== undefined"
|
||||
name="Proficiency"
|
||||
>
|
||||
<v-icon class="mr-4">
|
||||
<v-icon
|
||||
style="height: 12px"
|
||||
class="ml-1 mr-2"
|
||||
>
|
||||
{{ icon }}
|
||||
</v-icon>
|
||||
<div v-if="isFinite(model.value)">
|
||||
{{ numberToSignedString(model.value) }}
|
||||
<div>
|
||||
{{ proficiencyText[model.proficiency] }}
|
||||
</div>
|
||||
</div>
|
||||
</v-layout>
|
||||
<property-name :value="model.name" />
|
||||
<property-variable-name :value="model.variableName" />
|
||||
<property-field
|
||||
name="Ability"
|
||||
:value="model.ability"
|
||||
/>
|
||||
<property-field
|
||||
name="Type"
|
||||
:value="model.skillType"
|
||||
/>
|
||||
<property-field
|
||||
name="Base value"
|
||||
:value="model.baseValue"
|
||||
/>
|
||||
<property-field
|
||||
name="Base proficiency"
|
||||
:value="model.baseProficiency"
|
||||
/>
|
||||
</property-field>
|
||||
<property-field
|
||||
name="Variable Name"
|
||||
:value="model.variableName"
|
||||
/>
|
||||
<property-field
|
||||
name="Ability"
|
||||
:value="model.ability"
|
||||
/>
|
||||
<property-field
|
||||
name="Skill type"
|
||||
:value="model.skillType"
|
||||
/>
|
||||
</v-row>
|
||||
<property-description
|
||||
:string="model.description"
|
||||
:calculations="model.descriptionCalculations"
|
||||
:inactive="model.inactive"
|
||||
/>
|
||||
|
||||
<attribute-effect
|
||||
v-for="effect in baseEffects"
|
||||
:key="effect._id"
|
||||
:model="effect"
|
||||
:hide-breadcrumbs="effect._id === model._id"
|
||||
:data-id="effect._id"
|
||||
@click="effect._id !== model._id && clickEffect(effect._id)"
|
||||
/>
|
||||
<attribute-effect
|
||||
v-if="ability"
|
||||
:key="ability._id"
|
||||
:model="ability"
|
||||
:data-id="ability._id"
|
||||
@click="clickEffect(ability._id)"
|
||||
/>
|
||||
<attribute-effect
|
||||
v-for="effect in effects"
|
||||
:key="effect._id"
|
||||
:model="effect"
|
||||
:data-id="effect._id"
|
||||
@click="clickEffect(effect._id)"
|
||||
/>
|
||||
<skill-proficiency
|
||||
v-for="proficiency in baseProficiencies"
|
||||
:key="proficiency._id"
|
||||
:model="proficiency"
|
||||
:proficiency-bonus="proficiencyBonus"
|
||||
:hide-breadcrumbs="proficiency._id === model._id"
|
||||
:data-id="proficiency._id"
|
||||
@click="clickEffect(proficiency._id)"
|
||||
/>
|
||||
<skill-proficiency
|
||||
v-for="proficiency in proficiencies"
|
||||
:key="proficiency._id"
|
||||
:model="proficiency"
|
||||
:proficiency-bonus="proficiencyBonus"
|
||||
:data-id="proficiency._id"
|
||||
@click="clickEffect(proficiency._id)"
|
||||
/>
|
||||
<v-row
|
||||
v-if="baseEffects.length || ability || effects.length"
|
||||
dense
|
||||
>
|
||||
<property-field
|
||||
:cols="{col: 12}"
|
||||
name="Effects"
|
||||
>
|
||||
<v-list style="width: 100%">
|
||||
<attribute-effect
|
||||
v-for="effect in baseEffects"
|
||||
:key="effect._id === model._id ? 'this_base' : effect._id"
|
||||
:model="effect"
|
||||
:hide-breadcrumbs="effect._id === model._id"
|
||||
:data-id="effect._id"
|
||||
@click="effect._id !== model._id && clickEffect(effect._id)"
|
||||
/>
|
||||
<attribute-effect
|
||||
v-if="ability"
|
||||
:key="ability._id"
|
||||
:model="ability"
|
||||
:data-id="ability._id"
|
||||
@click="clickEffect(ability._id)"
|
||||
/>
|
||||
<attribute-effect
|
||||
v-for="effect in effects"
|
||||
:key="effect._id"
|
||||
:model="effect"
|
||||
:data-id="effect._id"
|
||||
@click="clickEffect(effect._id)"
|
||||
/>
|
||||
</v-list>
|
||||
</property-field>
|
||||
</v-row>
|
||||
<v-row
|
||||
v-if="baseProficiencies.length || proficiencies.length"
|
||||
dense
|
||||
>
|
||||
<property-field
|
||||
:cols="{col: 12}"
|
||||
name="Proficiencies"
|
||||
>
|
||||
<v-list style="width: 100%">
|
||||
<skill-proficiency
|
||||
v-for="proficiency in baseProficiencies"
|
||||
:key="proficiency._id"
|
||||
:model="proficiency"
|
||||
:proficiency-bonus="proficiencyBonus"
|
||||
:hide-breadcrumbs="proficiency._id === model._id"
|
||||
:data-id="proficiency._id"
|
||||
@click="clickEffect(proficiency._id)"
|
||||
/>
|
||||
<skill-proficiency
|
||||
v-for="proficiency in proficiencies"
|
||||
:key="proficiency._id"
|
||||
:model="proficiency"
|
||||
:proficiency-bonus="proficiencyBonus"
|
||||
:data-id="proficiency._id"
|
||||
@click="clickEffect(proficiency._id)"
|
||||
/>
|
||||
</v-list>
|
||||
</property-field>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -100,6 +130,15 @@ export default {
|
||||
inject: {
|
||||
context: { default: {} }
|
||||
},
|
||||
data(){return {
|
||||
proficiencyText: {
|
||||
0: 'Not proficient',
|
||||
1: 'Proficient',
|
||||
0.49: 'Half proficiency bonus rounded down',
|
||||
0.5: 'Half proficiency bonus rounded up',
|
||||
2: 'Double proficiency bonus',
|
||||
},
|
||||
}},
|
||||
computed: {
|
||||
displayedModifier(){
|
||||
let mod = this.model.value;
|
||||
@@ -139,23 +178,23 @@ export default {
|
||||
name: 'Skill base value',
|
||||
operation: 'base',
|
||||
calculation: prop.baseValueCalculation,
|
||||
result: prop.baseValue,
|
||||
amount: {value: prop.baseValue?.value},
|
||||
stats: [prop.variableName],
|
||||
ancestors: prop.ancestors,
|
||||
}) ).filter(effect => effect.result);
|
||||
}) ).filter(effect => effect.amount?.value);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
effects(){
|
||||
if (this.context.creatureId){
|
||||
if (this.context.creatureId && this.model.variableName){
|
||||
let creatureId = this.context.creatureId;
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': creatureId,
|
||||
stats: this.model.variableName,
|
||||
type: 'effect',
|
||||
removed: {$ne: true},
|
||||
});
|
||||
}).fetch();
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
@@ -189,7 +228,7 @@ export default {
|
||||
type: 'proficiency',
|
||||
removed: {$ne: true},
|
||||
inactive: {$ne: true},
|
||||
});
|
||||
}).fetch();
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
@@ -211,7 +250,7 @@ export default {
|
||||
_id: abilityProp._id,
|
||||
name: abilityProp.name,
|
||||
operation: 'base',
|
||||
result: abilityProp.modifier,
|
||||
amount: {value: abilityProp.modifier},
|
||||
stats: [this.model.variableName],
|
||||
ancestors: abilityProp.ancestors,
|
||||
}
|
||||
|
||||
@@ -1,21 +1,32 @@
|
||||
<template lang="html">
|
||||
<markdown-text
|
||||
<property-field
|
||||
v-if="model"
|
||||
:markdown="model.value"
|
||||
/>
|
||||
:name="label"
|
||||
:cols="{col: 12}"
|
||||
>
|
||||
<markdown-text
|
||||
:markdown="model.value || model.text"
|
||||
/>
|
||||
</property-field>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import MarkdownText from '/imports/ui/components/MarkdownText.vue';
|
||||
import PropertyField from '/imports/ui/properties/viewers/shared/PropertyField.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MarkdownText,
|
||||
PropertyField,
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
default: undefined,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,14 +1,42 @@
|
||||
<template lang="html">
|
||||
<div v-if="value !== undefined || $slots.default">
|
||||
<div class="text-caption">
|
||||
{{ name }}
|
||||
</div>
|
||||
<p class="ml-2 subheading">
|
||||
<slot>
|
||||
{{ value }}
|
||||
</slot>
|
||||
</p>
|
||||
</div>
|
||||
<v-col
|
||||
v-if="value !== undefined || ($slots.default && $slots.default.length)"
|
||||
v-bind="cols"
|
||||
class="mb-2"
|
||||
>
|
||||
<v-sheet
|
||||
outlined
|
||||
rounded
|
||||
class="pa-2 layout column align-start fill-height"
|
||||
>
|
||||
<v-sheet
|
||||
v-if="name"
|
||||
class="text-caption px-1 name"
|
||||
style="margin-top: -18px;"
|
||||
>
|
||||
{{ name }}
|
||||
</v-sheet>
|
||||
<div
|
||||
class="flex-grow-1 layout align-center"
|
||||
style="width: 100%;"
|
||||
>
|
||||
<div
|
||||
class="layout align-center"
|
||||
:class="{
|
||||
'text-body-1': !large,
|
||||
'text-h4': large,
|
||||
'justify-center': center,
|
||||
}"
|
||||
style="overflow-x: auto;"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<slot>
|
||||
{{ value }}
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</v-sheet>
|
||||
</v-col>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
@@ -16,9 +44,21 @@ export default {
|
||||
props: {
|
||||
name: String,
|
||||
value: [String, Number, Boolean],
|
||||
}
|
||||
center: Boolean,
|
||||
large: Boolean,
|
||||
cols: {
|
||||
type: Object,
|
||||
default: () => ({cols: 12, sm: 6, md: 4}),
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.name {
|
||||
color: rgba(0,0,0,.6);
|
||||
}
|
||||
.theme--dark .name {
|
||||
color: rgba(255,255,255,.7);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user