Moved ui/forms to ui/properties/forms
This commit is contained in:
34
app/imports/ui/properties/forms/shared/FormSection.vue
Normal file
34
app/imports/ui/properties/forms/shared/FormSection.vue
Normal 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>
|
||||
9
app/imports/ui/properties/forms/shared/FormSections.vue
Normal file
9
app/imports/ui/properties/forms/shared/FormSections.vue
Normal file
@@ -0,0 +1,9 @@
|
||||
<template lang="html">
|
||||
<v-expansion-panel popout expand>
|
||||
<slot/>
|
||||
</v-expansion-panel>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {}
|
||||
</script>
|
||||
92
app/imports/ui/properties/forms/shared/ProficiencySelect.vue
Normal file
92
app/imports/ui/properties/forms/shared/ProficiencySelect.vue
Normal 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>
|
||||
37
app/imports/ui/properties/forms/shared/propertyFormIndex.js
Normal file
37
app/imports/ui/properties/forms/shared/propertyFormIndex.js
Normal 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,
|
||||
};
|
||||
59
app/imports/ui/properties/forms/shared/schemaFormMixin.js
Normal file
59
app/imports/ui/properties/forms/shared/schemaFormMixin.js
Normal 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;
|
||||
Reference in New Issue
Block a user