Refactored UI folder structure

This commit is contained in:
Stefan Zermatten
2019-04-15 11:44:27 +02:00
parent 05867c61dd
commit dabb54b0a3
47 changed files with 59 additions and 59 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -1,11 +0,0 @@
<template lang="html">
<div>Todo</div>
</template>
<script>
export default {
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -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>

View File

@@ -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>

View File

@@ -1,11 +0,0 @@
<template lang="html">
<div>TODO</div>
</template>
<script>
export default {
}
</script>
<style lang="css" scoped>
</style>