Moved ui/forms to ui/properties/forms

This commit is contained in:
Stefan Zermatten
2019-08-01 12:07:57 +02:00
parent 9f7d6b8ae7
commit c87a3a3f60
34 changed files with 66 additions and 66 deletions

View File

@@ -0,0 +1,34 @@
<template lang="html">
<form-sections v-if="standalone">
<v-expansion-panel-content>
<div slot="header" class="subheading">
{{name}}
</div>
<v-card-text>
<slot/>
</v-card-text>
</v-expansion-panel-content>
</form-sections>
<v-expansion-panel-content v-else>
<div slot="header" class="subheading">
{{name}}
</div>
<v-card-text>
<slot/>
</v-card-text>
</v-expansion-panel-content>
</template>
<script>
import FormSections from '/imports/ui/properties/forms/shared/FormSections.vue';
export default {
components: {
FormSections,
},
props: {
name: String,
standalone: Boolean,
},
}
export { FormSections };
</script>

View File

@@ -0,0 +1,9 @@
<template lang="html">
<v-expansion-panel popout expand>
<slot/>
</v-expansion-panel>
</template>
<script>
export default {}
</script>

View File

@@ -0,0 +1,92 @@
<template lang="html">
<smart-select
append-icon="arrow_drop_down"
class="ml-3"
v-bind="$attrs"
:menu-props="{transition: 'slide-y-transition', lazy: true}"
:items="values"
:value="value"
@change="(value, ack) => $emit('change', value, ack)"
>
<v-icon
class="icon"
slot="prepend"
:class="iconClass"
>{{displayedIcon}}</v-icon>
</smart-select>
</template>
<script>
const ICON_SPIN_DURATION = 300;
let proficiencyIcon = function(value){
if (value == 0.5){
return 'brightness_2';
} else if (value == 1) {
return 'brightness_1'
} else if (value == 2){
return 'album'
} else {
return 'radio_button_unchecked';
}
};
export default {
props: {
value: Number,
},
data(){ return {
displayedIcon: 'radio_button_unchecked',
iconClass: '',
values: [
{value: 1, text: 'Proficient'},
{value: 0.5, text: 'Half proficiency bonus'},
{value: 2, text: 'Double proficiency bonus'},
],
}},
watch: {
'value': {
immediate: true,
handler(newValue, oldValue, e){
let newIcon = proficiencyIcon(newValue);
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;
}
</style>

View File

@@ -0,0 +1,37 @@
import ActionForm from '/imports/ui/properties/forms/ActionForm.vue';
import AttributeForm from '/imports/ui/properties/forms/AttributeForm.vue';
import BuffForm from '/imports/ui/properties/forms/BuffForm.vue';
import ContainerForm from '/imports/ui/properties/forms/ContainerForm.vue';
import ClassLevelForm from '/imports/ui/properties/forms/ClassLevelForm.vue';
import DamageMultiplierForm from '/imports/ui/properties/forms/DamageMultiplierForm.vue';
import EffectForm from '/imports/ui/properties/forms/EffectForm.vue';
import ExperienceForm from '/imports/ui/properties/forms/ExperienceForm.vue';
import FeatureForm from '/imports/ui/properties/forms/FeatureForm.vue';
import FolderForm from '/imports/ui/properties/forms/FolderForm.vue';
import ItemForm from '/imports/ui/properties/forms/ItemForm.vue';
import NoteForm from '/imports/ui/properties/forms/NoteForm.vue';
import ProficiencyForm from '/imports/ui/properties/forms/ProficiencyForm.vue';
import RollForm from '/imports/ui/properties/forms/RollForm.vue';
import SkillForm from '/imports/ui/properties/forms/SkillForm.vue';
import SpellListForm from '/imports/ui/properties/forms/SpellListForm.vue';
import SpellForm from '/imports/ui/properties/forms/SpellForm.vue';
export default {
action: ActionForm,
attribute: AttributeForm,
buff: BuffForm,
container: ContainerForm,
classLevel: ClassLevelForm,
damageMultiplier: DamageMultiplierForm,
experience:ExperienceForm,
effect: EffectForm,
feature: FeatureForm,
folder: FolderForm,
item: ItemForm,
note: NoteForm,
proficiency: ProficiencyForm,
roll: RollForm,
skill: SkillForm,
spellList: SpellListForm,
spell: SpellForm,
};

View File

@@ -0,0 +1,59 @@
/**
* Forms that take in a schema and a model of the current data, manages smart
* inputs, and sends update events when valid data model changes must occur
*/
import { get, toPath } from 'lodash';
function resolvePath(model, path){
let arrayPath = toPath(path);
if (arrayPath.length === 1){
return { object: model, key: arrayPath[0] };
}
let objectPath = arrayPath.slice(0, -1);
let key = arrayPath.slice(-1);
let object = get(model, objectPath);
return {object, key};
};
const schemaFormMixin = {
data(){ return {
valid: true,
};},
computed: {
errors(){
this.valid = true;
if (!this.model){
throw new Error("this.model must be set");
}
if (!this.validationContext) return {};
let cleanModel = this.validationContext.clean(this.model, {
getAutoValues: false,
});
this.validationContext.validate(cleanModel);
let errors = {};
this.validationContext.validationErrors().forEach(error => {
if (this.valid) this.valid = false;
errors[error.name] = this.schema.messageForError(error);
});
return errors;
},
},
methods: {
// Sets the value at the given path
change({path, value, ack}){
let {object, key} = resolvePath(this.model, path);
this.$set(object, key, value);
if (ack) ack();
},
push({path, value, ack}){
get(this.model, path).push(value);
if (ack) ack();
},
pull({path, ack}){
let {object, key} = resolvePath(this.model, path);
object.splice(key, 1);
if (ack) ack();
},
},
};
export default schemaFormMixin;