Refactored UI folder structure
This commit is contained in:
@@ -1,116 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-list>
|
||||
<template v-for="(ability, index) in abilities">
|
||||
<v-divider v-if="index !== 0"/>
|
||||
<ability-list-tile
|
||||
:key="ability.name"
|
||||
:data-id="`${_uid}-${ability.name}`"
|
||||
v-bind="ability"
|
||||
@click="click({ability, elementId: `${_uid}-${ability.name}`})"
|
||||
/>
|
||||
</template>
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AbilityListTile from '/imports/ui/components/attributes/AbilityListTile.vue';
|
||||
import store from "/imports/ui/vuexStore.js";
|
||||
|
||||
export default {
|
||||
data(){ return{
|
||||
abilities: [
|
||||
{
|
||||
name: "Strength",
|
||||
value: 8,
|
||||
mod: -1,
|
||||
effects: [
|
||||
{
|
||||
name: "Ghost Touch",
|
||||
operation: "add",
|
||||
result: -2,
|
||||
enabled: true,
|
||||
_id: Random.id(),
|
||||
},{
|
||||
name: "Some Base",
|
||||
operation: "base",
|
||||
result: 15,
|
||||
enabled: true,
|
||||
_id: Random.id(),
|
||||
},{
|
||||
name: "Some Multiply",
|
||||
operation: "mul",
|
||||
result: 1.5,
|
||||
enabled: true,
|
||||
_id: Random.id(),
|
||||
},{
|
||||
name: "Some Min",
|
||||
operation: "min",
|
||||
result: 8,
|
||||
enabled: true,
|
||||
_id: Random.id(),
|
||||
},{
|
||||
name: "Some Advantage",
|
||||
operation: "advantage",
|
||||
result: 1,
|
||||
enabled: true,
|
||||
_id: Random.id(),
|
||||
},{
|
||||
name: "Some Disadvantage",
|
||||
operation: "disadvantage",
|
||||
result: 1,
|
||||
enabled: true,
|
||||
_id: Random.id(),
|
||||
},{
|
||||
name: "Some Passive",
|
||||
operation: "passiveAdd",
|
||||
result: -2,
|
||||
calculation: "3-5",
|
||||
_id: Random.id(),
|
||||
},{
|
||||
name: "Some Conditional",
|
||||
operation: "conditional",
|
||||
calculation: "+8 Only when asleep",
|
||||
enabled: true,
|
||||
_id: Random.id(),
|
||||
},
|
||||
]
|
||||
}, {
|
||||
name: "Dexterity",
|
||||
value: 18,
|
||||
mod: 4,
|
||||
}, {
|
||||
name: "Constitution",
|
||||
value: 12,
|
||||
mod: 1,
|
||||
}, {
|
||||
name: "Intelligence",
|
||||
value: 20,
|
||||
mod: 5,
|
||||
}, {
|
||||
name: "Wisdom",
|
||||
value: 6,
|
||||
mod: -2,
|
||||
}, {
|
||||
name: "Charisma",
|
||||
value: 28,
|
||||
mod: 9,
|
||||
},
|
||||
]
|
||||
}},
|
||||
components: {
|
||||
AbilityListTile,
|
||||
},
|
||||
methods: {
|
||||
click({ability, elementId}){
|
||||
store.commit("pushDialogStack", {
|
||||
component: "attribute-dialog",
|
||||
elementId,
|
||||
data: ability,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,66 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-list-tile class="ability-list-tile" v-on="hasClickListener ? {click} : {}">
|
||||
|
||||
<v-list-tile-action class="mr-4">
|
||||
<div class="display-1 mod">
|
||||
{{numberToSignedString(mod)}}
|
||||
</div>
|
||||
<div class="title value">
|
||||
{{value}}
|
||||
</div>
|
||||
</v-list-tile-action>
|
||||
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>
|
||||
{{name}}
|
||||
</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
|
||||
</v-list-tile>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
export default {
|
||||
props: {
|
||||
value: Number,
|
||||
mod: Number,
|
||||
name: String,
|
||||
},
|
||||
methods: {
|
||||
numberToSignedString,
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
hasClickListener(){
|
||||
return this.$listeners && this.$listeners.click
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.ability-list-tile {
|
||||
background: inherit;
|
||||
}
|
||||
.ability-list-tile >>> .v-list__tile {
|
||||
height: 88px;
|
||||
}
|
||||
.ability-list-tile >>> .v-list__tile__action--stack {
|
||||
justify-content: center;
|
||||
}
|
||||
.value {
|
||||
font-weight: 600;
|
||||
font-size: 24px !important;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
.theme--dark .value {
|
||||
color: rgba(255, 255, 255, 0.54);
|
||||
}
|
||||
.mod, .value {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -1,43 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-container grid-list-md>
|
||||
<v-layout row wrap>
|
||||
<v-flex xs12 v-for="attribute in attributes" :key="attribute.name">
|
||||
<attribute-card v-bind="attribute" @click="click"/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AttributeCard from '/imports/ui/components/attributes/AttributeCard.vue';
|
||||
export default {
|
||||
components: {
|
||||
AttributeCard
|
||||
},
|
||||
dontWrap: true,
|
||||
data(){ return {
|
||||
attributes: [
|
||||
{
|
||||
name: 'Speed',
|
||||
value: 30,
|
||||
}, {
|
||||
name: 'Initiative',
|
||||
value: 2,
|
||||
modifier: true,
|
||||
},{
|
||||
name: 'Proficiency Bonus',
|
||||
value: -2,
|
||||
modifier: true,
|
||||
},
|
||||
],
|
||||
}},
|
||||
methods: {
|
||||
click() {
|
||||
console.log(...arguments)
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,43 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-card :hover="hasClickListener" @click="click">
|
||||
<v-card-text>
|
||||
<div class="layout row align-center">
|
||||
<div class="value display-1 mr-1">
|
||||
{{modifier ? signed(value) : value}}
|
||||
</div>
|
||||
<div class="name text-truncate">
|
||||
{{name}}
|
||||
</div>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
export default {
|
||||
props: {
|
||||
name: String,
|
||||
value: Number,
|
||||
modifier: Boolean,
|
||||
},
|
||||
methods: {
|
||||
signed: numberToSignedString,
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
hasClickListener(){
|
||||
return this.$listeners && !!this.$listeners.click
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.value {
|
||||
min-width: 64px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,84 +0,0 @@
|
||||
<template lang="html">
|
||||
<dialog-base>
|
||||
<div slot="toolbar">
|
||||
New Attribute
|
||||
</div>
|
||||
<attribute-edit
|
||||
:attribute="attribute"
|
||||
:errors="errors"
|
||||
@change="change"
|
||||
:debounce-time="0"
|
||||
/>
|
||||
<v-spacer slot="actions"/>
|
||||
<v-btn
|
||||
flat
|
||||
slot="actions"
|
||||
:disabled="!valid"
|
||||
@click="$store.dispatch('popDialogStack', attribute)"
|
||||
>
|
||||
Insert Attribute
|
||||
</v-btn>
|
||||
</dialog-base>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AttributeEdit from '/imports/ui/components/attributes/AttributeEdit.vue';
|
||||
import Attributes from '/imports/api/creature/properties/Attributes.js';
|
||||
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AttributeEdit,
|
||||
DialogBase,
|
||||
},
|
||||
data(){ return {
|
||||
attribute: {
|
||||
name: 'New Attribute',
|
||||
variableName: 'newAttribute',
|
||||
type: 'stat',
|
||||
baseValue: null,
|
||||
adjustment: null,
|
||||
decimal: null,
|
||||
reset: null,
|
||||
color: '#9E9E9E',
|
||||
},
|
||||
valid: true,
|
||||
}},
|
||||
methods: {
|
||||
change(update, ack){
|
||||
for (key in update){
|
||||
this.attribute[key] = update[key];
|
||||
if (key === 'name' && update[key]){
|
||||
const name = update[key];
|
||||
this.attribute.variableName = name.toLowerCase().replace(
|
||||
/\W+(\w?)/g, (match, p1) => p1.toUpperCase()
|
||||
);
|
||||
}
|
||||
}
|
||||
if (ack) ack();
|
||||
},
|
||||
},
|
||||
created(){
|
||||
this.validationContext = Attributes.simpleSchema().newContext();
|
||||
},
|
||||
computed: {
|
||||
errors(){
|
||||
this.valid = true;
|
||||
let cleanAtt = this.validationContext.clean(this.attribute)
|
||||
this.validationContext.validate(cleanAtt, {keys: [
|
||||
'name', 'variableName', 'type', 'baseValue', 'adjustment', 'decimal',
|
||||
'reset', 'color'
|
||||
]});
|
||||
let errors = {};
|
||||
this.validationContext.validationErrors().forEach(error => {
|
||||
if (this.valid) this.valid = false;
|
||||
errors[error.name] = Attributes.simpleSchema().messageForError(error);
|
||||
});
|
||||
return errors;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,100 +0,0 @@
|
||||
<template lang="html">
|
||||
<dialog-base>
|
||||
<div slot="toolbar">
|
||||
{{name}}
|
||||
</div>
|
||||
<div>
|
||||
<v-layout align-center column v-if="type === 'ability'">
|
||||
<div class="display-3 mod">
|
||||
{{numberToSignedString(mod)}}
|
||||
</div>
|
||||
<div class="display-1 ability-value">
|
||||
{{value}}
|
||||
</div>
|
||||
</v-layout>
|
||||
<div class="display-3 attribute-value" v-else-if="type === 'healthBar'">
|
||||
{{value+adjustment}} / {{value}}
|
||||
</div>
|
||||
<div class="display-3 attribute-value" v-else-if="type === 'modifier'">
|
||||
{{numberToSignedString(value)}}
|
||||
</div>
|
||||
<div class="display-3 attribute-value" v-else>
|
||||
{{value}}
|
||||
</div>
|
||||
<effect-child-list v-if="attribueBaseEffect" :effects="[attribueBaseEffect]"/>
|
||||
<div v-if="effects && effects.length">
|
||||
<h6 class="title">Effects</h6>
|
||||
<effect-child-list :effects="effects" @click="clickedEffect"/>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="edit">
|
||||
<attribute-edit :attribute="$props" @change="(update, ack) => $emit('change', update, ack)"/>
|
||||
</div>
|
||||
</dialog-base>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DialogBase from "/imports/ui/dialogStack/DialogBase.vue";
|
||||
import EffectChildList from '/imports/ui/components/children/effects/EffectChildList.vue';
|
||||
import AttributeEdit from '/imports/ui/components/attributes/AttributeEdit.vue';
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
charId: String,
|
||||
name: String,
|
||||
variableName: String,
|
||||
order: Number,
|
||||
type: String,
|
||||
baseValue: Number,
|
||||
value: Number,
|
||||
mod: Number,
|
||||
adjustment: Number,
|
||||
decimal: Boolean,
|
||||
reset: String,
|
||||
resetMultiplier: Number,
|
||||
color: String,
|
||||
adjustment: {type: Number, default: 0},
|
||||
effects: {type: Array, default: () => []},
|
||||
},
|
||||
methods: {
|
||||
numberToSignedString,
|
||||
clickedEffect(e){
|
||||
this.$emit('clickedEffect', e);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
attribueBaseEffect(){
|
||||
if (!this.baseValue) return;
|
||||
return {
|
||||
_id: 'attributeBaseValue',
|
||||
name: `${this.name}`,
|
||||
operation: 'base',
|
||||
result: this.baseValue,
|
||||
stat: this.variableName,
|
||||
enabled: true,
|
||||
};
|
||||
},
|
||||
},
|
||||
components: {
|
||||
DialogBase,
|
||||
EffectChildList,
|
||||
AttributeEdit,
|
||||
},
|
||||
};
|
||||
</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;
|
||||
}
|
||||
</style>
|
||||
@@ -1,64 +0,0 @@
|
||||
<template lang="html">
|
||||
<attribute-dialog
|
||||
v-bind="attribute"
|
||||
:effects="effects"
|
||||
v-on="{clickedEffect, change}"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AttributeDialog from '/imports/ui/components/attributes/AttributeDialog.vue';
|
||||
import Attributes from '/imports/api/creature/properties/Attributes.js';
|
||||
import {
|
||||
updateAttribute,
|
||||
adjustAttribute
|
||||
} from '/imports/api/creature/properties/Attributes.js';
|
||||
import Effects from '/imports/api/creature/properties/Effects.js';
|
||||
import { setName } from '/imports/api/parenting/parenting.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AttributeDialog,
|
||||
},
|
||||
props: {
|
||||
_id: String,
|
||||
},
|
||||
meteor: {
|
||||
attribute(){
|
||||
return Attributes.findOne(this._id);
|
||||
},
|
||||
effects(){
|
||||
if (!this.attribute) return;
|
||||
let charId = this.attribute.charId;
|
||||
let stat = this.attribute.variableName;
|
||||
return Effects.find({
|
||||
charId,
|
||||
stat,
|
||||
enabled: true,
|
||||
}, {
|
||||
sort: {order: 1},
|
||||
}).fetch();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clickedEffect(e){
|
||||
console.log({TODO: e});
|
||||
},
|
||||
change(update, ack){
|
||||
if (update.name){
|
||||
setName.call({})
|
||||
} if (update)
|
||||
updateAttribute.call({
|
||||
_id: this._id,
|
||||
update: {$set: update}
|
||||
}, error => {
|
||||
ack(error);
|
||||
if (error) console.error(error);
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,58 +0,0 @@
|
||||
<template lang="html">
|
||||
<div>
|
||||
<attribute-edit
|
||||
v-for="(attribute, index) in attributes"
|
||||
:key="attribute._id"
|
||||
:attribute="attribute"
|
||||
@change="(e, ack) => change(index, e, ack)"
|
||||
/>
|
||||
<div class="ma-4" v-for="(attribute, index) in attributes">
|
||||
{{attribute}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AttributeEdit from '/imports/ui/components/attributes/AttributeEdit.vue';
|
||||
import debounceUpdate from '/imports/ui/utility/debounceUpdate.js';
|
||||
export default {
|
||||
components: {
|
||||
AttributeEdit,
|
||||
},
|
||||
data(){ return {
|
||||
attributes: [
|
||||
{
|
||||
_id: Random.id(),
|
||||
name: 'Strength',
|
||||
variableName: 'strength',
|
||||
order: 4,
|
||||
type: 'ability',
|
||||
baseValue: 10,
|
||||
value: 14,
|
||||
mod: 2,
|
||||
adjustment: -2,
|
||||
decimal: false,
|
||||
reset: undefined,
|
||||
resetMultiplier: undefined,
|
||||
color: '#aa0000',
|
||||
},
|
||||
],
|
||||
}},
|
||||
methods: {
|
||||
change(index, e, ack){
|
||||
// Take a while to write the attribute
|
||||
setTimeout(() => {
|
||||
for (let i in e){
|
||||
let val = e[i];
|
||||
if (typeof val === 'string') val = val.trim();
|
||||
this.attributes[index][i] = val;
|
||||
}
|
||||
if (ack) ack();
|
||||
}, 600)
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,127 +0,0 @@
|
||||
<template lang="html">
|
||||
<div>
|
||||
<text-field
|
||||
label="Name"
|
||||
:value="attribute.name"
|
||||
@change="(name, ack) => $emit('change', {name}, ack)"
|
||||
:error-messages="errors.name"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<text-field
|
||||
label="Variable name"
|
||||
:value="attribute.variableName"
|
||||
@change="(variableName, ack) => $emit('change', {variableName}, ack)"
|
||||
hint="Use this name in formulae to reference this attribute"
|
||||
:error-messages="errors.variableName"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<text-field
|
||||
label="Base Value"
|
||||
type="number"
|
||||
:value="attribute.baseValue"
|
||||
@change="(baseValue, ack) => $emit('change', {baseValue: +baseValue}, ack)"
|
||||
hint="This is the value of the attribute before effects are applied"
|
||||
:error-messages="errors.baseValue"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<text-field
|
||||
label="Damage"
|
||||
type="number"
|
||||
:value="-attribute.adjustment"
|
||||
@change="(damage, ack) => $emit('change', {adjustment: -damage || null}, ack)"
|
||||
:error-messages="errors.adjustment"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<smart-select
|
||||
label="Type"
|
||||
:items="attributeTypes"
|
||||
:value="attribute.type"
|
||||
:error-messages="errors.type"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(type, ack) => $emit('change', {type}, ack)"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<v-switch
|
||||
label="Allow decimal values"
|
||||
:value="attribute.decimal"
|
||||
:error-messages="errors.decimal"
|
||||
@change="e => $emit('change', {decimal: !!e})"
|
||||
/>
|
||||
<smart-select
|
||||
label="Reset"
|
||||
clearable
|
||||
:items="resetOptions"
|
||||
:value="attribute.reset"
|
||||
:error-messages="errors.reset"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(reset, ack) => $emit('change', {reset}, ack)"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<text-field
|
||||
label="Reset Multiplier"
|
||||
type="number"
|
||||
:value="attribute.resetMultiplier"
|
||||
:error-messages="errors.resetMultiplier"
|
||||
@change="(resetMultiplier, ack) => $emit('change', {resetMultiplier: +resetMultiplier}, ack)"
|
||||
hint="Some attributes, like hit dice, only reset by half their total on a long rest"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
attribute: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
errors: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
debounceTime: Number,
|
||||
},
|
||||
data(){ return{
|
||||
attributeTypes: [
|
||||
{
|
||||
text: 'Ability score',
|
||||
value: 'ability',
|
||||
}, {
|
||||
text: 'Stat',
|
||||
value: 'stat',
|
||||
}, {
|
||||
text: 'Modifier',
|
||||
value: 'modifier',
|
||||
}, {
|
||||
text: 'Hit dice',
|
||||
value: 'hitDice',
|
||||
}, {
|
||||
text: 'Health bar',
|
||||
value: 'healthBar',
|
||||
}, {
|
||||
text: 'Resource',
|
||||
value: 'resource',
|
||||
}, {
|
||||
text: 'Spell slot',
|
||||
value: 'spellSlot',
|
||||
}, {
|
||||
text: 'Utility',
|
||||
value: 'utility',
|
||||
},
|
||||
],
|
||||
resetOptions: [
|
||||
{
|
||||
text: 'Short rest',
|
||||
value: 'shortRest',
|
||||
}, {
|
||||
text: 'Long rest',
|
||||
value: 'longRest',
|
||||
}
|
||||
]
|
||||
}},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,60 +0,0 @@
|
||||
<template lang="html">
|
||||
<div class="pa-1" style="background: inherit;">
|
||||
<health-bar
|
||||
:value="value"
|
||||
:max-value="maxValue"
|
||||
name="Hit Points"
|
||||
@change="healthBarChanged"
|
||||
/>
|
||||
<health-bar
|
||||
:value="50"
|
||||
:max-value="100"
|
||||
name="Temporary Hit Points"
|
||||
/>
|
||||
<health-bar
|
||||
:value="70"
|
||||
:max-value="100"
|
||||
name="Some other bar"
|
||||
@change="healthBarChanged"
|
||||
/>
|
||||
<health-bar
|
||||
:value="90"
|
||||
:max-value="100"
|
||||
name="Cow"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HealthBar from '/imports/ui/components/attributes/HealthBar.vue';
|
||||
export default {
|
||||
data(){return{
|
||||
value: 100,
|
||||
maxValue: 100,
|
||||
}},
|
||||
components: {
|
||||
HealthBar,
|
||||
},
|
||||
methods: {
|
||||
healthBarChanged(e){
|
||||
let val = e.value;
|
||||
// Apply the change
|
||||
if (e.type === 'set'){
|
||||
this.value = val;
|
||||
} else if (e.type === 'increment') {
|
||||
this.value += val;
|
||||
}
|
||||
// Clamp the value
|
||||
if (this.value < 0){
|
||||
this.value = 0;
|
||||
}
|
||||
if (this.value > this.maxValue){
|
||||
this.value = this.maxValue;
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,228 +0,0 @@
|
||||
<template>
|
||||
<v-layout
|
||||
row
|
||||
wrap
|
||||
align-center
|
||||
justify-center
|
||||
style="min-height: 48px;"
|
||||
:class="{ hover }"
|
||||
class="my-3 health-bar"
|
||||
:data-id="_id"
|
||||
>
|
||||
<div
|
||||
class="subheading text-truncate pa-2 name"
|
||||
@mouseover="hover = true"
|
||||
@mouseleave="hover = false"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
{{ name }}
|
||||
</div>
|
||||
<v-flex style="height: 20px; flex-basis: 300px; flex-grow: 100;">
|
||||
<v-layout
|
||||
column
|
||||
align-center
|
||||
@click="edit"
|
||||
style="cursor: pointer;"
|
||||
class="bar"
|
||||
>
|
||||
<v-progress-linear
|
||||
:value="(value / maxValue) * 100"
|
||||
height="20"
|
||||
color="green lighten-1"
|
||||
class="ma-0"
|
||||
>
|
||||
</v-progress-linear>
|
||||
<span
|
||||
class="value"
|
||||
style="margin-top: -20px; z-index: 1; font-size: 16px; font-weight: 600; height: 20px;"
|
||||
>
|
||||
{{ value }} / {{ maxValue }}
|
||||
</span>
|
||||
</v-layout>
|
||||
<transition name="transition">
|
||||
<v-toolbar
|
||||
v-if="editing"
|
||||
justify-center
|
||||
height="48"
|
||||
flat
|
||||
class="transparent toolbar"
|
||||
>
|
||||
<v-spacer />
|
||||
<v-btn-toggle
|
||||
v-model="operation"
|
||||
@click="$refs.editInput.focus()"
|
||||
class="mr-2"
|
||||
>
|
||||
<v-btn @click="$nextTick(() => $refs.editInput.focus())" class="filled">
|
||||
<v-icon>add</v-icon>
|
||||
</v-btn>
|
||||
<v-btn @click="$nextTick(() => $refs.editInput.focus())" class="filled">
|
||||
<v-icon>remove</v-icon>
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
<v-text-field
|
||||
solo
|
||||
hide-details
|
||||
type="number"
|
||||
v-if="editing"
|
||||
ref="editInput"
|
||||
style="max-width: 120px;"
|
||||
min="0"
|
||||
:value="editValue"
|
||||
:prepend-inner-icon="operation === 0 ? 'add' : operation === 1 ? 'remove' : 'forward'"
|
||||
@focus="$event.target.select()"
|
||||
@keyup.enter="commitEdit"
|
||||
@keypress.43="
|
||||
operation === 0 ? (operation = null) : (operation = 0)
|
||||
"
|
||||
@keypress.45="
|
||||
operation === 1 ? (operation = null) : (operation = 1)
|
||||
"
|
||||
@keypress="rejectNonNumbers($event)"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-btn small fab @click="commitEdit" class="filled" color="red">
|
||||
<v-icon>done</v-icon>
|
||||
</v-btn>
|
||||
<v-btn small fab @click="cancelEdit" class="mx-0 filled">
|
||||
<v-icon>close</v-icon>
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
</v-toolbar>
|
||||
</transition>
|
||||
</v-flex>
|
||||
<transition name="background-transition">
|
||||
<div v-if="editing" class="page-tint" @click="cancelEdit" />
|
||||
</transition>
|
||||
</v-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
editing: false,
|
||||
editValue: 0,
|
||||
operation: null,
|
||||
hover: false,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
value: Number,
|
||||
maxValue: Number,
|
||||
name: String,
|
||||
_id: String,
|
||||
},
|
||||
methods: {
|
||||
edit() {
|
||||
this.editing = true;
|
||||
this.operation = null;
|
||||
this.editValue = this.value;
|
||||
this.$nextTick(function() {
|
||||
this.$refs.editInput.focus();
|
||||
console.log()
|
||||
});
|
||||
},
|
||||
cancelEdit() {
|
||||
this.editing = false;
|
||||
},
|
||||
commitEdit() {
|
||||
this.editing = false;
|
||||
let value = +this.$refs.editInput.lazyValue;
|
||||
let type = this.operation === null ? 'set' : 'increment';
|
||||
if (this.operation === 1) {
|
||||
value = -value;
|
||||
}
|
||||
this.$emit('change', { type, value });
|
||||
},
|
||||
rejectNonNumbers: function(evt) {
|
||||
evt = evt ? evt : window.event;
|
||||
var charCode = evt.which ? evt.which : evt.keyCode;
|
||||
if (
|
||||
(charCode > 31 && (charCode < 48 || charCode > 57)) ||
|
||||
charCode === 46
|
||||
) {
|
||||
evt.preventDefault();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.health-bar {
|
||||
background: inherit;
|
||||
}
|
||||
.name {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
min-width: 150px;
|
||||
flex-basis: 150px;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
.name:hover {
|
||||
font-weight: 500;
|
||||
}
|
||||
.bar {
|
||||
transition: box-shadow 0.2s;
|
||||
}
|
||||
.bar:hover {
|
||||
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),
|
||||
0 1px 5px 0 rgba(0, 0, 0, 0.12) !important;
|
||||
}
|
||||
.toolbar {
|
||||
margin-left: -50%;
|
||||
margin-right: -50%;
|
||||
width: 200%;
|
||||
margin-top: -34px !important;
|
||||
z-index: 4;
|
||||
}
|
||||
.hover {
|
||||
background: #f5f5f5 !important;
|
||||
}
|
||||
.theme--dark .hover {
|
||||
background: #515151 !important;
|
||||
}
|
||||
.filled.theme--light {
|
||||
background: #fff !important;
|
||||
}
|
||||
.filled.theme--dark {
|
||||
background: #424242 !important;
|
||||
}
|
||||
.background-transition-enter-active,
|
||||
.background-transition-leave-active {
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.background-transition-enter,
|
||||
.background-transition-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
.transition-enter-active {
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.transition-leave-active {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.transition-enter-to,
|
||||
.transition-leave {
|
||||
opacity: 1;
|
||||
transform: scaleY(1) !important;
|
||||
}
|
||||
.transition-enter,
|
||||
.transition-leave-to {
|
||||
opacity: 0;
|
||||
transform: scaleY(0) !important;
|
||||
}
|
||||
.page-tint {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
z-index: 3;
|
||||
}
|
||||
</style>
|
||||
@@ -1,27 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-card class="pa-2">
|
||||
<health-bar
|
||||
v-for="attribute in attributes"
|
||||
:key="attribute._id"
|
||||
:value="attribute.value + (attribute.adjustment || 0)"
|
||||
:maxValue="attribute.value"
|
||||
:name="attribute.name"
|
||||
:_id="attribute._id"
|
||||
@change="e => $emit('change', {_id: attribute._id, change: e})"
|
||||
@click="e => $emit('click', {_id: attribute._id})"
|
||||
/>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HealthBar from '/imports/ui/components/attributes/HealthBar.vue';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
attributes: Array,
|
||||
},
|
||||
components: {
|
||||
HealthBar,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,48 +0,0 @@
|
||||
<template lang="html">
|
||||
<health-bar-card
|
||||
:attributes="attributes"
|
||||
@change="healthBarChanged"
|
||||
@click="healthBarClicked"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Attributes from '/imports/api/creature/properties/Attributes.js';
|
||||
import { adjustAttribute } from '/imports/api/creature/properties/Attributes.js';
|
||||
import HealthBarCard from '/imports/ui/components/attributes/HealthBarCard.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HealthBarCard,
|
||||
},
|
||||
props: {
|
||||
charId: String,
|
||||
},
|
||||
meteor: {
|
||||
attributes(){
|
||||
return Attributes.find({
|
||||
charId: this.charId,
|
||||
type: 'healthBar',
|
||||
value: {$ne: 0},
|
||||
}, {
|
||||
sort: {order: 1},
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
healthBarClicked({_id}){
|
||||
this.$store.commit("pushDialogStack", {
|
||||
component: "attribute-dialog-container",
|
||||
elementId: _id,
|
||||
data: {_id},
|
||||
});
|
||||
},
|
||||
healthBarChanged({_id, change}){
|
||||
adjustAttribute.call({
|
||||
_id,
|
||||
[change.type]: change.value
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,66 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-list>
|
||||
<v-subheader>Hit Dice</v-subheader>
|
||||
<template v-for="(hitDie, index) in hitDice">
|
||||
<v-divider v-if="index !== 0"/>
|
||||
<hit-dice-list-tile
|
||||
:key="hitDie.dice"
|
||||
v-bind="hitDie"
|
||||
@click="click"
|
||||
@change="e => change(hitDie, e)"
|
||||
/>
|
||||
</template>
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HitDiceListTile from '/imports/ui/components/attributes/HitDiceListTile.vue';
|
||||
export default {
|
||||
data(){ return{
|
||||
hitDice: [
|
||||
{
|
||||
dice: 6,
|
||||
value: 20,
|
||||
maxValue: 20,
|
||||
conMod: 4,
|
||||
}, {
|
||||
dice: 8,
|
||||
value: 3,
|
||||
maxValue: 3,
|
||||
conMod: 4,
|
||||
}, {
|
||||
dice: 10,
|
||||
value: 3,
|
||||
maxValue: 3,
|
||||
conMod: 4,
|
||||
}, {
|
||||
dice: 12,
|
||||
value: 1,
|
||||
maxValue: 1,
|
||||
conMod: 4,
|
||||
},
|
||||
]
|
||||
}},
|
||||
components: {
|
||||
HitDiceListTile,
|
||||
},
|
||||
methods: {
|
||||
click(e){
|
||||
console.log(e);
|
||||
},
|
||||
change(hitDie, e){
|
||||
if (e.type === 'increment'){
|
||||
hitDie.value += e.value;
|
||||
if (hitDie.value > hitDie.maxValue){
|
||||
hitDie.value = hitDie.maxValue;
|
||||
} else if (hitDie.value < 0){
|
||||
hitDie.value = 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,97 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-list-tile class="hit-dice-list-tile" :class="{hover}">
|
||||
|
||||
<v-list-tile-action class="mr-4">
|
||||
|
||||
<v-layout row align-center class="left">
|
||||
<v-layout column class="buttons" justify-center>
|
||||
<v-btn icon small :disabled="value >= maxValue" @click="increment(1)">
|
||||
<v-icon>arrow_drop_up</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon small :disabled="value <= 0" @click="increment(-1)">
|
||||
<v-icon>arrow_drop_down</v-icon>
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
|
||||
<v-layout row align-end>
|
||||
<div class="display-1">
|
||||
{{value}}
|
||||
</div>
|
||||
<div class="title max-value ml-2">
|
||||
/{{maxValue}}
|
||||
</div>
|
||||
</v-layout>
|
||||
</v-layout>
|
||||
|
||||
</v-list-tile-action>
|
||||
|
||||
<v-list-tile-content
|
||||
class="content"
|
||||
@click="click"
|
||||
@mouseover="hover = true"
|
||||
@mouseleave="hover = false"
|
||||
>
|
||||
<v-list-tile-title>
|
||||
d{{dice}} {{signed(conMod)}}
|
||||
</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
|
||||
</v-list-tile>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
export default {
|
||||
data(){ return{
|
||||
hover: false,
|
||||
}},
|
||||
props: {
|
||||
dice: Number,
|
||||
value: Number,
|
||||
maxValue: Number,
|
||||
conMod: Number,
|
||||
},
|
||||
methods: {
|
||||
signed: numberToSignedString,
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
increment(value){
|
||||
this.$emit('change', {type: 'increment', value})
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.hit-dice-list-tile {
|
||||
background: inherit;
|
||||
}
|
||||
.hit-dice-list-tile >>> .v-list__tile {
|
||||
height: 88px;
|
||||
}
|
||||
.left {
|
||||
height: 100%;
|
||||
}
|
||||
.buttons {
|
||||
height: 100%;
|
||||
}
|
||||
.buttons > .v-btn {
|
||||
margin: 0;
|
||||
}
|
||||
.hit-dice-list-tile.hover {
|
||||
background: #f5f5f5 !important;
|
||||
}
|
||||
.theme--dark .hit-dice-list-tile.hover {
|
||||
background: #515151 !important;
|
||||
}
|
||||
.content {
|
||||
cursor: pointer;
|
||||
}
|
||||
.max-value {
|
||||
color: rgba(0,0,0,.54);
|
||||
}
|
||||
.theme--dark .max-value {
|
||||
color: rgba(255, 255, 255, 0.54);
|
||||
}
|
||||
</style>
|
||||
@@ -1,47 +0,0 @@
|
||||
<template lang="html">
|
||||
<column-layout>
|
||||
<div>
|
||||
<resource-card
|
||||
data-id="abc123"
|
||||
name="Sorcery points"
|
||||
color="#f44336"
|
||||
:value="8"
|
||||
:adjustment="-2"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<resource-card
|
||||
data-id="abc123"
|
||||
name="Psionic point like things"
|
||||
color="#f44336"
|
||||
:value="34"
|
||||
:adjustment="-12"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<resource-card
|
||||
data-id="abc123"
|
||||
name="Rages"
|
||||
color="#f44336"
|
||||
:value="1"
|
||||
:adjustment="0"
|
||||
/>
|
||||
</div>
|
||||
</column-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ResourceCard from '/imports/ui/components/attributes/ResourceCard.vue';
|
||||
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
|
||||
|
||||
export default {
|
||||
dontWrap: true,
|
||||
components: {
|
||||
ColumnLayout,
|
||||
ResourceCard,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,79 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-card class="resource-card layout row" :class="hover ? 'elevation-8': ''">
|
||||
<div class="buttons layout column justify-center pl-3">
|
||||
<v-btn icon small :disabled="currentValue >= value" @click="increment(1)">
|
||||
<v-icon>arrow_drop_up</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon small :disabled="currentValue <= 0" @click="increment(-1)">
|
||||
<v-icon>arrow_drop_down</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<div
|
||||
class="layout row align-center value pl-2 pr-3"
|
||||
>
|
||||
<div class="display-1">{{currentValue}}</div>
|
||||
<div class="title ml-2 max-value">/{{value}}</div>
|
||||
</div>
|
||||
<div
|
||||
class="content layout row align-center pr-3"
|
||||
@click="click"
|
||||
@mouseover="hover = true"
|
||||
@mouseleave="hover = false"
|
||||
>
|
||||
<div class="text-truncate ">
|
||||
{{name}}
|
||||
</div>
|
||||
</div>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data(){ return{
|
||||
hover: false,
|
||||
}},
|
||||
props: {
|
||||
_id: String,
|
||||
name: String,
|
||||
color: String,
|
||||
value: Number,
|
||||
adjustment: Number,
|
||||
},
|
||||
computed: {
|
||||
currentValue(){
|
||||
return this.value + (this.adjustment || 0);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
increment(value){
|
||||
this.$emit('change', {type: 'increment', value})
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.resource-card > div {
|
||||
padding-top: 16px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.buttons, .value {
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
}
|
||||
.buttons > .v-btn {
|
||||
margin: 0;
|
||||
}
|
||||
.content {
|
||||
cursor: pointer;
|
||||
}
|
||||
.max-value {
|
||||
color: rgba(0,0,0,.54);
|
||||
}
|
||||
.theme--dark .max-value {
|
||||
color: rgba(255, 255, 255, 0.54);
|
||||
}
|
||||
</style>
|
||||
@@ -1,44 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-list>
|
||||
<spell-slot-list-tile
|
||||
v-for="(slot, index) in spellSlots"
|
||||
:key="'tile ' + index"
|
||||
v-bind="slot"
|
||||
@change="e => spellSlots[index].adjustment += e.value"
|
||||
/>
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SpellSlotListTile from '/imports/ui/components/attributes/SpellSlotListTile.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SpellSlotListTile,
|
||||
},
|
||||
data(){return {
|
||||
spellSlots: [
|
||||
{
|
||||
name: "Level 1",
|
||||
value: 4,
|
||||
adjustment: -2,
|
||||
}, {
|
||||
name: "Level 1",
|
||||
value: 1,
|
||||
adjustment: 0,
|
||||
}, {
|
||||
name: "Level 2",
|
||||
value: 12,
|
||||
adjustment: -8,
|
||||
}, {
|
||||
name: "Level 3",
|
||||
value: 10,
|
||||
adjustment: -5,
|
||||
},
|
||||
],
|
||||
}}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,122 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-list-tile class="spell-slot-list-tile" :class="{hover}">
|
||||
|
||||
<v-list-tile-action>
|
||||
|
||||
<div class="layout row align-center" v-if="value > 4">
|
||||
<div class="buttons layout column justify-center">
|
||||
<v-btn icon small :disabled="currentValue >= value" @click="increment(1)">
|
||||
<v-icon>arrow_drop_up</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon small :disabled="currentValue <= 0" @click="increment(-1)">
|
||||
<v-icon>arrow_drop_down</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<div class="layout row value" style="align-items: baseline;">
|
||||
<div class="display-1">{{currentValue}}</div>
|
||||
<div class="title ml-2 max-value">/{{value}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layout row align-center justify-end slot-buttons" v-else>
|
||||
<v-btn
|
||||
icon
|
||||
small
|
||||
v-for="i in value"
|
||||
:disabled="!(i === currentValue || i === currentValue + 1)"
|
||||
:key="i"
|
||||
@click="increment(i > currentValue ? 1 : -1)"
|
||||
>
|
||||
<v-icon>{{
|
||||
i > currentValue ?
|
||||
'radio_button_unchecked' :
|
||||
'radio_button_checked'
|
||||
}}</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
</v-list-tile-action>
|
||||
|
||||
<v-list-tile-content
|
||||
class="content ml-2"
|
||||
@click="click"
|
||||
@mouseover="hover = true"
|
||||
@mouseleave="hover = false"
|
||||
>
|
||||
<v-list-tile-title>
|
||||
{{name}}
|
||||
</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
export default {
|
||||
data(){ return{
|
||||
hover: false,
|
||||
}},
|
||||
props: {
|
||||
_id: String,
|
||||
name: String,
|
||||
color: String,
|
||||
value: Number,
|
||||
adjustment: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
currentValue(){
|
||||
return this.value + (this.adjustment || 0);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
signed: numberToSignedString,
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
increment(value){
|
||||
this.$emit('change', {type: 'increment', value})
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.spell-slot-list-tile {
|
||||
background: inherit;
|
||||
}
|
||||
.spell-slot-list-tile >>> .v-list__tile {
|
||||
height: 56px;
|
||||
}
|
||||
.v-list__tile__action {
|
||||
width: 112px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.slot-buttons > .v-btn {
|
||||
margin: 0;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
.buttons {
|
||||
height: 100%;
|
||||
}
|
||||
.buttons > .v-btn {
|
||||
margin: 0;
|
||||
}
|
||||
.spell-slot-list-tile.hover {
|
||||
background: #f5f5f5 !important;
|
||||
}
|
||||
.theme--dark .spell-slot-list-tile.hover {
|
||||
background: #515151 !important;
|
||||
}
|
||||
.content {
|
||||
cursor: pointer;
|
||||
}
|
||||
.max-value {
|
||||
color: rgba(0,0,0,.54);
|
||||
}
|
||||
.theme--dark .max-value {
|
||||
color: rgba(255, 255, 255, 0.54);
|
||||
}
|
||||
</style>
|
||||
@@ -1,34 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-list two-line v-if="this.effects && this.effects.length">
|
||||
<effect-list-tile
|
||||
:show-stat-name="showStatName"
|
||||
v-for="effect in sortedEffects"
|
||||
v-bind="effect"
|
||||
v-on="$listeners.click ? { click(e){$emit('click', e)} } : {}"
|
||||
:key="effect._id"
|
||||
/>
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EffectListTile from '/imports/ui/components/children/effects/EffectListTile.vue';
|
||||
import sortEffects from '/imports/ui/utility/sortEffects.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
effects: Array,
|
||||
showStatName: Boolean,
|
||||
},
|
||||
components: {
|
||||
EffectListTile,
|
||||
},
|
||||
computed: {
|
||||
sortedEffects(){
|
||||
return sortEffects(this.effects);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,51 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-card-text>
|
||||
<template v-for="(effect, index) in effects">
|
||||
<v-divider v-if="index != 0"/>
|
||||
<effect-edit :key="index" :effect="effect" :stats="stats" @change="e => change(index, e)"/>
|
||||
</template>
|
||||
</v-card-text>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EffectEdit from '/imports/ui/components/children/effects/EffectEdit.vue';
|
||||
export default {
|
||||
data(){ return {
|
||||
effects: [
|
||||
{
|
||||
operation: 'add',
|
||||
calculation: '2',
|
||||
stat: '',
|
||||
},
|
||||
{
|
||||
operation: 'mul',
|
||||
calculation: '2',
|
||||
stat: 'strength',
|
||||
},
|
||||
{
|
||||
operation: 'base',
|
||||
calculation: 'strength + 4',
|
||||
result: 6,
|
||||
stat: 'dexterity',
|
||||
},
|
||||
],
|
||||
stats: [
|
||||
{name: "Strength", variableName: "strength"},
|
||||
],
|
||||
}},
|
||||
components: {
|
||||
EffectEdit,
|
||||
},
|
||||
methods: {
|
||||
change(index, e){
|
||||
for (let i in e){
|
||||
this.effects[index][i] = e[i];
|
||||
console.log({e, effect: this.effects[index]})
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,155 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-layout row wrap class="effect-edit py-4 px-2">
|
||||
|
||||
<!-- Operation -->
|
||||
<v-flex class="ma-1">
|
||||
<smart-select
|
||||
label="Operation"
|
||||
append-icon="arrow_drop_down"
|
||||
:menu-props="{transition: 'slide-y-transition', lazy: true}"
|
||||
:items="operations"
|
||||
:value="this.effect.operation"
|
||||
@change="(operation, ack) => $emit('change', {set: {operation}, ack})"
|
||||
>
|
||||
<v-icon
|
||||
class="icon"
|
||||
slot="prepend"
|
||||
:class="iconClass"
|
||||
>{{displayedIcon}}</v-icon>
|
||||
<template slot="item" slot-scope="item">
|
||||
<v-icon
|
||||
class="icon mr-2"
|
||||
>{{getEffectIcon(item.item.value, 1)}}</v-icon>
|
||||
{{item.item.text}}
|
||||
</template>
|
||||
</smart-select>
|
||||
</v-flex>
|
||||
|
||||
<!-- Value -->
|
||||
<v-flex class="ma-1">
|
||||
<text-field
|
||||
label="Value"
|
||||
:persistent-hint="needsValue"
|
||||
:value="needsValue ? (effect.calculation) : ' '"
|
||||
:disabled="!needsValue"
|
||||
:hint="!isFinite(effect.calculation) && effect.result ? effect.result + '' : '' "
|
||||
@change="(calculation, ack) => $emit('change', {set: {calculation}, ack})"
|
||||
/>
|
||||
</v-flex>
|
||||
|
||||
<!-- Stat -->
|
||||
<v-flex class="ma-1">
|
||||
<v-autocomplete
|
||||
label="Stat"
|
||||
append-icon="arrow_drop_down"
|
||||
item-text="name"
|
||||
item-value="variableName"
|
||||
:menu-props="{transition: 'slide-y-transition', lazy: true}"
|
||||
:value="effect.stat"
|
||||
:items="stats"
|
||||
@input="stat => $emit('change', {set: {stat}, ack: () => {} })"
|
||||
/>
|
||||
</v-flex>
|
||||
|
||||
</v-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import getEffectIcon from '/imports/ui/utility/getEffectIcon.js';
|
||||
|
||||
const ICON_SPIN_DURATION = 300;
|
||||
export default {
|
||||
props: {
|
||||
effect: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
stats: {
|
||||
type: Array,
|
||||
},
|
||||
},
|
||||
data(){ return {
|
||||
displayedIcon: 'add',
|
||||
iconClass: '',
|
||||
operations: [
|
||||
{value: 'base', text: 'Base Value'},
|
||||
{value: 'add', text: 'Add'},
|
||||
{value: 'mul', text: 'Multiply'},
|
||||
{value: 'min', text: 'Minimum'},
|
||||
{value: 'max', text: 'Maximum'},
|
||||
{value: 'advantage', text: 'Advantage'},
|
||||
{value: 'disadvantage', text: 'Disadvantage'},
|
||||
{value: 'passiveAdd', text: 'Passive Bonus'},
|
||||
{value: 'fail', text: 'Fail'},
|
||||
{value: 'conditional', text: 'Conditional Benefit'},
|
||||
],
|
||||
}},
|
||||
computed: {
|
||||
needsValue(){
|
||||
switch(this.effect.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 true;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getEffectIcon,
|
||||
},
|
||||
watch: {
|
||||
'effect.operation': {
|
||||
immediate: true,
|
||||
handler(newValue, oldValue, e){
|
||||
let newIcon = getEffectIcon(newValue, 1);
|
||||
if (!oldValue){
|
||||
// Skip animation
|
||||
this.displayedIcon = newIcon;
|
||||
} else {
|
||||
this.iconClass="leaving";
|
||||
setTimeout(() => {
|
||||
this.displayedIcon = newIcon;
|
||||
this.iconClass="arriving";
|
||||
requestAnimationFrame(() => {
|
||||
this.iconClass="";
|
||||
});
|
||||
}, ICON_SPIN_DURATION / 2);
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.theme--light .icon {
|
||||
color: black;
|
||||
}
|
||||
.icon {
|
||||
min-width: 30px;
|
||||
transition: transform 0.15s linear, opacity 0.15s ease;
|
||||
transform-origin: 18px center;
|
||||
margin-left: -12px;
|
||||
}
|
||||
.icon.leaving {
|
||||
transform: translateY(-24px);
|
||||
opacity: 0;
|
||||
}
|
||||
.icon.arriving {
|
||||
transform: translateY(24px);
|
||||
opacity: 0;
|
||||
transition: none;
|
||||
}
|
||||
.hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
.flex {
|
||||
width: 220px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,104 +0,0 @@
|
||||
<template lang="html">
|
||||
<effect-edit-expansion-list
|
||||
:effects="effects"
|
||||
:stats="stats"
|
||||
@change="change"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EffectEditExpansionList from '/imports/ui/components/children/effects/EffectEditExpansionList.vue';
|
||||
export default {
|
||||
data(){ return {
|
||||
effects: [
|
||||
{
|
||||
name: "Ghost Touch",
|
||||
stat: 'Strength',
|
||||
operation: "add",
|
||||
result: -2,
|
||||
calculation: '-2',
|
||||
enabled: true,
|
||||
_id: Random.id(),
|
||||
},{
|
||||
name: "Some Base",
|
||||
stat: 'Strength',
|
||||
operation: "base",
|
||||
result: 15,
|
||||
calculation: '15',
|
||||
enabled: true,
|
||||
_id: Random.id(),
|
||||
},{
|
||||
name: "Some Multiply",
|
||||
stat: 'Strength',
|
||||
operation: "mul",
|
||||
result: 1.5,
|
||||
calculation: '1.5',
|
||||
enabled: true,
|
||||
_id: Random.id(),
|
||||
},{
|
||||
name: "Some Min",
|
||||
stat: 'Strength',
|
||||
operation: "min",
|
||||
result: 8,
|
||||
calculation: '8',
|
||||
enabled: true,
|
||||
_id: Random.id(),
|
||||
},{
|
||||
name: "Some Advantage",
|
||||
stat: 'Strength',
|
||||
operation: "advantage",
|
||||
result: 1,
|
||||
calculation: '1',
|
||||
enabled: true,
|
||||
_id: Random.id(),
|
||||
},{
|
||||
name: "Some Disadvantage",
|
||||
stat: 'Strength',
|
||||
operation: "disadvantage",
|
||||
result: 1,
|
||||
calculation: '1',
|
||||
enabled: true,
|
||||
_id: Random.id(),
|
||||
},{
|
||||
name: "Some Passive",
|
||||
stat: 'Strength',
|
||||
operation: "passiveAdd",
|
||||
result: -2,
|
||||
calculation: '-2',
|
||||
calculation: "3-5",
|
||||
_id: Random.id(),
|
||||
},{
|
||||
name: "Some Conditional",
|
||||
stat: 'Strength',
|
||||
operation: "conditional",
|
||||
calculation: "+8 Only when asleep",
|
||||
result: "+8 Only when asleep",
|
||||
enabled: true,
|
||||
_id: Random.id(),
|
||||
},
|
||||
],
|
||||
stats: ["Strength", "Dexterity", "Constitution", "Speed"].map( a => ({
|
||||
name: a,
|
||||
variableName: a,
|
||||
})),
|
||||
}},
|
||||
components: {
|
||||
EffectEditExpansionList,
|
||||
},
|
||||
methods: {
|
||||
change({set, ack, effectId, index}){
|
||||
console.log({set, ack, effectId, index});
|
||||
for (let key in set){
|
||||
this.effects[index][key] = set[key];
|
||||
if (key === 'calculation'){
|
||||
this.effects[index].result = set[key]
|
||||
}
|
||||
ack();
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,54 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-expansion-panel
|
||||
class="effect-edit-expansion-list"
|
||||
v-model="expanded"
|
||||
>
|
||||
<v-expansion-panel-content
|
||||
v-for="(effect, index) in effects"
|
||||
:key="effect._id"
|
||||
lazy
|
||||
>
|
||||
<effect-list-tile
|
||||
slot="header"
|
||||
class="effect-list-tile"
|
||||
:class="{'primary--text': expanded === index}"
|
||||
v-bind="effect"
|
||||
/>
|
||||
<effect-edit
|
||||
:effect="effect"
|
||||
:stats="stats"
|
||||
@change="({set, ack}) => $emit('change', {set, ack, effectId: effect._id, index})"
|
||||
/>
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EffectEdit from '/imports/ui/components/children/effects/EffectEdit.vue';
|
||||
import EffectListTile from '/imports/ui/components/children/effects/EffectListTile.vue';
|
||||
export default {
|
||||
props: {
|
||||
effects: Array,
|
||||
stats: Array,
|
||||
},
|
||||
components: {
|
||||
EffectEdit,
|
||||
EffectListTile,
|
||||
},
|
||||
data(){ return {
|
||||
expanded: null,
|
||||
}},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.effect-edit-expansion-list >>> .v-expansion-panel__header {
|
||||
padding-left: 0;
|
||||
padding-right: 8px;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.effect-list-tile {
|
||||
width: calc(100% - 26px);
|
||||
}
|
||||
</style>
|
||||
@@ -1,110 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-list-tile
|
||||
class="effect-list-tile"
|
||||
:class="{disabled: !enabled}"
|
||||
:data-id="_id"
|
||||
v-on="$listeners.click ? { click(e){
|
||||
$emit('click', $props)
|
||||
} } : {}"
|
||||
>
|
||||
<v-layout row align-center class="net-effect">
|
||||
<v-icon class="icon">{{getEffectIcon(operation, result)}}</v-icon>
|
||||
<div class="value display-1 pr-2" v-if="showValue(operation)">
|
||||
{{getValue(operation, result)}}
|
||||
</div>
|
||||
<div class="calculation body-2 pr-2" v-else>
|
||||
{{operation === 'conditional' ? calculation : ''}}
|
||||
</div>
|
||||
</v-layout>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title class="stat" v-if="showStatName">
|
||||
{{statName}}
|
||||
</v-list-tile-title>
|
||||
<v-list-tile-title class="name" v-else>
|
||||
{{name}}
|
||||
</v-list-tile-title>
|
||||
<v-list-tile-sub-title class="operation">
|
||||
{{getOperation(operation)}}
|
||||
</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
import getEffectIcon from '/imports/ui/utility/getEffectIcon.js';
|
||||
export default {
|
||||
props: {
|
||||
_id: String,
|
||||
enabled: Boolean,
|
||||
operation: String,
|
||||
result: [String, Number],
|
||||
calculation: String,
|
||||
name: String,
|
||||
stat: String,
|
||||
statName: String,
|
||||
showStatName: Boolean,
|
||||
},
|
||||
methods: {
|
||||
getEffectIcon,
|
||||
getOperation(op, value){
|
||||
switch(op) {
|
||||
case 'base': return 'Base value';
|
||||
case 'add': return 'Add';
|
||||
case 'mul': return 'Multiply';
|
||||
case 'min': return 'Minimum';
|
||||
case 'max': return 'Maximum';
|
||||
case 'advantage': return 'Advantage';
|
||||
case 'disadvantage': return 'Disadvantage';
|
||||
case 'passiveAdd': return 'Passive bonus';
|
||||
case 'fail': return 'Always fail';
|
||||
case 'conditional': return 'Conditional benefit' ;
|
||||
}
|
||||
},
|
||||
showValue(op){
|
||||
switch(op) {
|
||||
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;
|
||||
}
|
||||
},
|
||||
getValue(op, value){
|
||||
switch(op) {
|
||||
case 'base': return value;
|
||||
case 'add': return Math.abs(value);
|
||||
case 'mul': return value;
|
||||
case 'min': return value;
|
||||
case 'max': return value;
|
||||
case 'advantage': return;
|
||||
case 'disadvantage': return;
|
||||
case 'passiveAdd': return Math.abs(value);
|
||||
case 'fail': return;
|
||||
case 'conditional': return;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.icon {
|
||||
min-width: 30px;
|
||||
}
|
||||
.icon {
|
||||
color: inherit !important;
|
||||
}
|
||||
.net-effect {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.value, .calculation {
|
||||
min-width: 80px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,51 +0,0 @@
|
||||
<template lang="html">
|
||||
<column-layout>
|
||||
<div
|
||||
v-for="(feature, index) in features"
|
||||
:key="index"
|
||||
>
|
||||
<feature-card
|
||||
v-bind="feature"
|
||||
/>
|
||||
</div>
|
||||
</column-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
|
||||
import FeatureCard from '/imports/ui/components/features/FeatureCard.vue';
|
||||
|
||||
export default {
|
||||
dontWrap: true,
|
||||
components: {
|
||||
ColumnLayout,
|
||||
FeatureCard,
|
||||
},
|
||||
data(){return {
|
||||
features: [
|
||||
{
|
||||
name: 'Feature 1',
|
||||
enabled: true,
|
||||
alwaysEnabled: true,
|
||||
description: `
|
||||
|
||||
blah blah, with
|
||||
|
||||
spacing
|
||||
`,
|
||||
color: '#f44336',
|
||||
}, {
|
||||
name: 'Feature 2',
|
||||
enabled: false,
|
||||
alwaysEnabled: false,
|
||||
description: `Short Description`,
|
||||
uses: 5,
|
||||
used: 2,
|
||||
},
|
||||
],
|
||||
}},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css' scoped>
|
||||
</style>
|
||||
@@ -1,44 +0,0 @@
|
||||
<template lang="html">
|
||||
<toolbar-card :color="color" @click="$emit('click')" :id="_id">
|
||||
<template slot="toolbar">
|
||||
<span>
|
||||
{{name}}
|
||||
</span>
|
||||
<v-spacer/>
|
||||
<v-checkbox
|
||||
hide-details
|
||||
class="shrink"
|
||||
v-if="!alwaysEnabled"
|
||||
:value="enabled"
|
||||
@click.stop="$emit('update', {_id, update: {enabled: !enabled}})"
|
||||
/>
|
||||
</template>
|
||||
<v-card-text v-if="description">
|
||||
<markdown-text :markdown="description"/>
|
||||
</v-card-text>
|
||||
</toolbar-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MarkdownText from '/imports/ui/components/MarkdownText.vue';
|
||||
import ToolbarCard from '/imports/ui/components/ToolbarCard.vue';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
_id: String,
|
||||
charId: String,
|
||||
name: String,
|
||||
description: String,
|
||||
color: String,
|
||||
enabled: Boolean,
|
||||
alwaysEnabled: Boolean,
|
||||
},
|
||||
components: {
|
||||
MarkdownText,
|
||||
ToolbarCard,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,50 +0,0 @@
|
||||
<template lang="html">
|
||||
<property-insert-dialog
|
||||
documentType="Feature"
|
||||
:doc="feature"
|
||||
:schema="schema"
|
||||
:errors.sync="errors"
|
||||
>
|
||||
<feature-form
|
||||
:feature="feature"
|
||||
@update="update"
|
||||
:debounce-time="0"
|
||||
:errors="errors"
|
||||
/>
|
||||
</property-insert-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FeatureForm from '/imports/ui/components/features/FeatureForm.vue';
|
||||
import Features, { FeatureSchema } from '/imports/api/creature/properties/Features.js';
|
||||
import PropertyInsertDialog from '/imports/ui/components/properties/PropertyInsertDialog.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FeatureForm,
|
||||
PropertyInsertDialog,
|
||||
},
|
||||
data(){ return {
|
||||
feature: {
|
||||
name: 'New Feature',
|
||||
description: null,
|
||||
enabled: true,
|
||||
alwaysEnabled: true,
|
||||
color: '#9E9E9E',
|
||||
},
|
||||
schema: FeatureSchema,
|
||||
errors: {},
|
||||
}},
|
||||
methods: {
|
||||
update(update, ack){
|
||||
for (key in update){
|
||||
this.feature[key] = update[key];
|
||||
}
|
||||
ack();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,33 +0,0 @@
|
||||
<template lang="html">
|
||||
<property-dialog :doc="feature" collection="features" @remove="$emit('remove')">
|
||||
<div>
|
||||
<markdown-text :markdown="feature.computedDescription || feature.description"/>
|
||||
<!--
|
||||
<child-lists
|
||||
:parent="feature"
|
||||
/>
|
||||
-->
|
||||
</div>
|
||||
<feature-form slot="form" :feature="feature" @update="(update, ack) => $emit('update', update, ack)"/>
|
||||
</property-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PropertyDialog from '/imports/ui/components/properties/PropertyDialog.vue';
|
||||
import FeatureForm from '/imports/ui/components/features/FeatureForm.vue';
|
||||
import MarkdownText from '/imports/ui/components/MarkdownText.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PropertyDialog,
|
||||
FeatureForm,
|
||||
MarkdownText,
|
||||
},
|
||||
props: {
|
||||
feature: Object,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,42 +0,0 @@
|
||||
<template lang="html">
|
||||
<feature-dialog
|
||||
:feature="feature"
|
||||
@update="update"
|
||||
@remove="remove"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Features, {updateFeature} from '/imports/api/creature/properties/Features.js';
|
||||
import FeatureDialog from '/imports/ui/components/features/FeatureDialog.vue';
|
||||
import {evaluateStringForCharId} from '/imports/ui/utility/evaluate.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FeatureDialog,
|
||||
},
|
||||
props: {
|
||||
_id: String,
|
||||
},
|
||||
meteor: {
|
||||
feature(){
|
||||
let feature = Features.findOne(this._id);
|
||||
feature.computedDescription = evaluateStringForCharId(
|
||||
feature.description, feature.charId
|
||||
);
|
||||
return feature;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
update(update, ack){
|
||||
updateFeature.call({
|
||||
_id: this._id,
|
||||
update,
|
||||
}, error => ack(error));
|
||||
},
|
||||
remove(){
|
||||
softRemoveProperty({_id: this._id, collection: 'features'});
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,79 +0,0 @@
|
||||
<template lang="html">
|
||||
<div>
|
||||
<text-field
|
||||
label="Name"
|
||||
:value="feature.name"
|
||||
@change="(name, ack) => $emit('update', {name}, ack)"
|
||||
:error-messages="errors.name"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<smart-select
|
||||
label="Enabled"
|
||||
:items="enabledOptions"
|
||||
:value="enabledStatus"
|
||||
:error-messages="errors.enabled || errors.alwaysEnabled"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="changeEnabled"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<text-area
|
||||
label="Description"
|
||||
:value="feature.description"
|
||||
:error-messages="errors.description"
|
||||
@change="(description, ack) => $emit('update', {description}, ack)"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
feature: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
errors: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
debounceTime: Number,
|
||||
},
|
||||
data(){ return{
|
||||
enabledOptions: [
|
||||
{
|
||||
text: 'Always enabled',
|
||||
value: 'always',
|
||||
}, {
|
||||
text: 'Enabled',
|
||||
value: 'enabled',
|
||||
}, {
|
||||
text: 'Disabled',
|
||||
value: 'disabled',
|
||||
}
|
||||
],
|
||||
}},
|
||||
computed: {
|
||||
enabledStatus(){
|
||||
if (!this.feature) return;
|
||||
if (this.feature.alwaysEnabled) return 'always';
|
||||
if (this.feature.enabled) return 'enabled';
|
||||
return 'disabled';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
changeEnabled(value, ack){
|
||||
if (value === 'always'){
|
||||
this.$emit('update', {enabled: true, alwaysEnabled: true}, ack);
|
||||
} else if (value === 'enabled'){
|
||||
this.$emit('update', {enabled: true, alwaysEnabled: false}, ack);
|
||||
} else if (value === 'disabled'){
|
||||
this.$emit('update', {enabled: false, alwaysEnabled: false}, ack);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,108 +0,0 @@
|
||||
<template lang="html">
|
||||
<dialog-base class="skill-dialog">
|
||||
<div slot="toolbar">
|
||||
{{name}}
|
||||
</div>
|
||||
<div>
|
||||
<v-layout align-center justify-center>
|
||||
<skill-list-tile v-bind="$props"/>
|
||||
</v-layout>
|
||||
<skill-proficiency-list v-if="skillBaseProficiency" :effects="[skillBaseProficiency]"/>
|
||||
<effect-child-list v-if="skillAbilityEffect" :effects="[skillAbilityEffect]"/>
|
||||
<effect-child-list v-if="skillBaseEffect" :effects="[skillBaseEffect]"/>
|
||||
|
||||
<div v-if="proficiencies && proficiencies.length">
|
||||
<h6 class="title">Proficiencies</h6>
|
||||
<skill-proficiency-list :proficiencies="proficiencies" @click="clickedProficiency"/>
|
||||
</div>
|
||||
<div v-if="effects && effects.length">
|
||||
<h6 class="title">Effects</h6>
|
||||
<effect-child-list :effects="effects" @click="clickedEffect"/>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="edit">
|
||||
<skill-edit :skill="$props" @change="(update, ack) => $emit('change', update, ack)"/>
|
||||
</div>
|
||||
</dialog-base>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EffectChildList from '/imports/ui/components/children/effects/EffectChildList.vue';
|
||||
import DialogBase from "/imports/ui/dialogStack/DialogBase.vue";
|
||||
import SkillEdit from '/imports/ui/components/skills/SkillEdit.vue';
|
||||
import SkillProficiencyList from '/imports/ui/components/skills/SkillProficiencyList.vue';
|
||||
import SkillListTile from '/imports/ui/components/skills/SkillListTile.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EffectChildList,
|
||||
DialogBase,
|
||||
SkillEdit,
|
||||
SkillListTile,
|
||||
SkillProficiencyList,
|
||||
},
|
||||
props: {
|
||||
charId: String,
|
||||
name: String,
|
||||
variableName: String,
|
||||
ability: String,
|
||||
type: String,
|
||||
order: Number,
|
||||
baseValue: Number,
|
||||
baseProficiency: Number,
|
||||
value: Number,
|
||||
abilityMod: Number,
|
||||
advantage: Number,
|
||||
passiveBonus: Number,
|
||||
proficiency: Number,
|
||||
conditionalBenefits: Number,
|
||||
fail: Number,
|
||||
effects: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
proficiencies: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
abilityDoc: Object,
|
||||
},
|
||||
computed: {
|
||||
skillBaseEffect(){
|
||||
if (!this.baseValue) return;
|
||||
return {
|
||||
_id: 'skillBaseValue',
|
||||
name: `${this.name}`,
|
||||
operation: 'base',
|
||||
result: this.baseValue,
|
||||
stat: this.variableName,
|
||||
enabled: true,
|
||||
};
|
||||
},
|
||||
skillAbilityEffect(){
|
||||
if (!this.abilityDoc) return;
|
||||
return {
|
||||
_id: 'skillBaseValue',
|
||||
name: this.abilityDoc.name,
|
||||
operation: 'add',
|
||||
result: this.abilityMod,
|
||||
stat: this.variableName,
|
||||
enabled: true,
|
||||
};
|
||||
},
|
||||
skillBaseProficiency(){
|
||||
if (!this.baseProficiency) return;
|
||||
return {
|
||||
_id: 'skillBaseValue',
|
||||
name: `${this.name}`,
|
||||
value: this.baseProficiency,
|
||||
skill: this.variableName,
|
||||
enabled: true,
|
||||
};
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,78 +0,0 @@
|
||||
<template lang="html">
|
||||
<skill-dialog
|
||||
v-bind="skill"
|
||||
:effects="effects"
|
||||
:proficiencies="proficiencies"
|
||||
:abilityDoc="abilityDoc"
|
||||
v-on="{clickedEffect, clickedProficiency, change}"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import SkillDialog from '/imports/ui/components/skills/SkillDialog.vue';
|
||||
import Skills from '/imports/api/creature/properties/Skills.js';
|
||||
import { updateSkill } from '/imports/api/creature/properties/Skills.js';
|
||||
import Attributes from '/imports/api/creature/properties/Attributes.js';
|
||||
import Effects from '/imports/api/creature/properties/Effects.js';
|
||||
import Proficiencies from '/imports/api/creature/properties/Proficiencies.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SkillDialog,
|
||||
},
|
||||
props: {
|
||||
_id: String,
|
||||
},
|
||||
meteor: {
|
||||
skill(){
|
||||
return Skills.findOne(this._id);
|
||||
},
|
||||
abilityDoc(){
|
||||
return this.skill && Attributes.findOne({
|
||||
variableName: this.skill.ability,
|
||||
});
|
||||
},
|
||||
effects(){
|
||||
if (!this.skill) return;
|
||||
let charId = this.skill.charId;
|
||||
let stat = this.skill.variableName;
|
||||
return Effects.find({
|
||||
charId,
|
||||
stat,
|
||||
enabled: true,
|
||||
}, {
|
||||
sort: {order: 1},
|
||||
}).fetch();
|
||||
},
|
||||
proficiencies(){
|
||||
if (!this.skill) return;
|
||||
let charId = this.skill.charId;
|
||||
let stat = this.skill.variableName;
|
||||
return Proficiencies.find({
|
||||
charId,
|
||||
stat,
|
||||
enabled: true,
|
||||
}, {
|
||||
sort: {order: 1},
|
||||
}).fetch();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clickedEffect(e){
|
||||
console.log(e);
|
||||
},
|
||||
clickedProficiency(e){
|
||||
console.log(e);
|
||||
},
|
||||
change(update, ack){
|
||||
updateSkill.call({_id: this._id, update}, error => {
|
||||
ack(error);
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,11 +0,0 @@
|
||||
<template lang="html">
|
||||
<div>Todo</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,56 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-list>
|
||||
<skill-list-tile
|
||||
v-for="skill in skills"
|
||||
:key="skill.name"
|
||||
v-bind="skill"
|
||||
@click="click"
|
||||
/>
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SkillListTile from '/imports/ui/components/skills/SkillListTile.vue';
|
||||
export default {
|
||||
data(){return {
|
||||
skills: [
|
||||
{
|
||||
name: 'Animal Handling',
|
||||
proficiency: 1,
|
||||
value: 4,
|
||||
}, {
|
||||
name: 'Deception',
|
||||
proficiency: 0,
|
||||
value: -0,
|
||||
advantage: 0,
|
||||
}, {
|
||||
name: 'Intimidation',
|
||||
proficiency: 2,
|
||||
value: 6,
|
||||
advantage: 1,
|
||||
}, {
|
||||
name: 'Insight',
|
||||
proficiency: 0.5,
|
||||
value: -2,
|
||||
advantage: -1,
|
||||
}, {
|
||||
name: 'History',
|
||||
conditionalBenefits: 1,
|
||||
fail: 1,
|
||||
advantage: -1,
|
||||
}
|
||||
]
|
||||
}},
|
||||
components: {
|
||||
SkillListTile,
|
||||
},
|
||||
methods: {
|
||||
click(){
|
||||
console.log(...arguments);
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,78 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-list-tile class="skill-list-tile" height="32px" v-on="hasClickListener ? {click} : {}">
|
||||
<v-list-tile-action class="prof-icon">
|
||||
<v-icon>{{icon}}</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>
|
||||
<span class="prof-mod">
|
||||
{{displayedModifier}}
|
||||
</span>
|
||||
{{name}}<template v-if="conditionalBenefits">*</template>
|
||||
<v-icon size="20px" v-if="advantage > 0">arrow_upward</v-icon>
|
||||
<v-icon size="20px" v-if="advantage < 0">arrow_downward</v-icon>
|
||||
</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
proficiency: Number,
|
||||
advantage: Number,
|
||||
fail: Number,
|
||||
value: Number,
|
||||
name: String,
|
||||
conditionalBenefits: Number,
|
||||
},
|
||||
methods: {
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
icon(){
|
||||
if (this.proficiency == 0.5){
|
||||
return 'brightness_2';
|
||||
} else if (this.proficiency == 1) {
|
||||
return 'brightness_1'
|
||||
} else if (this.proficiency == 2){
|
||||
return 'album'
|
||||
} else {
|
||||
return 'radio_button_unchecked';
|
||||
}
|
||||
},
|
||||
displayedModifier(){
|
||||
let mod = this.value;
|
||||
if (this.fail){
|
||||
return 'fail';
|
||||
} else {
|
||||
return numberToSignedString(mod);
|
||||
}
|
||||
},
|
||||
hasClickListener(){
|
||||
return this.$listeners && this.$listeners.click
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.skill-list-tile >>> .v-list__tile {
|
||||
height: 34px;
|
||||
}
|
||||
.skill-list-tile{
|
||||
background: inherit;
|
||||
}
|
||||
.prof-icon {
|
||||
min-width: 30px;
|
||||
}
|
||||
.prof-mod {
|
||||
display: inline-block;
|
||||
width: 45px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,11 +0,0 @@
|
||||
<template lang="html">
|
||||
<div>TODO</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
Reference in New Issue
Block a user