Cobbled together some semblance of an item library UI

This commit is contained in:
Stefan Zermatten
2018-10-02 15:43:10 +02:00
parent f4d3368fb4
commit f5a32cb50a
19 changed files with 775 additions and 27 deletions

View File

@@ -0,0 +1,88 @@
<template name="libraryItemDialog">
<div class="fit base-dialog layout vertical">
<app-toolbar>
<paper-icon-button id="backButton"
icon="arrow-back">
</paper-icon-button>
<div main-title>{{item.name}}</div>
<paper-icon-button id="deleteButton"
role="button"
tabindex="0"
icon="delete">
</paper-icon-button>
</app-toolbar>
<div class="form flex scroll-y" style="position: relative;">
<paper-input id="libraryItemLibraryNameInput" class="fullwidth" label="Library name (optional)" value={{item.libraryName}}></paper-input>
<paper-input id="libraryItemNameInput" class="fullwidth" label="Item name" value={{item.name}}></paper-input>
<div class="layout horizontal center wrap">
<paper-input id="libraryItemPluralInput" class="flex" label="Plural name" value={{item.plural}}></paper-input>
<paper-input id="libraryItemQuantityInput" class="flex" label="Quantity" type="number" value={{item.quantity}}></paper-input>
<paper-checkbox id="incrementCheckbox" class="flex" checked={{item.settings.showIncrement}}>
Show Increment
</paper-checkbox>
</div>
<div class="layout horizontal center wrap">
<paper-input id="libraryItemValueInput" class="flex" label="Value" type="number" value={{item.value}}></paper-input>
<paper-input id="libraryItemWeightInput" class="flex" label="Weight" type="number" value={{item.weight}}></paper-input>
<paper-checkbox id="attunementCheckbox" class="flex" checked={{item.requiresAttunement}}>
Requires Attunement
</paper-checkbox>
</div>
<paper-textarea id="libraryItemDescriptionInput" label="Description" value={{item.description}}></paper-textarea>
<div style="margin-top: 8px;">
<div class="paper-font-subhead">Effects</div>
{{#each indexedEffects}}
<div class="effect layout horizontal center wrap">
<paper-dropdown-menu label="Operation" class="operationMenu">
<paper-listbox class="dropdown-content" selected={{operationIndex operation}}>
<paper-item label="Base Value" name="base"> Base Value </paper-item>
<paper-item label="Add" name="add"> Add </paper-item>
<paper-item label="Multiply" name="mul"> Multiply </paper-item>
<paper-item label="Min" name="min"> Min </paper-item>
<paper-item label="Max" name="max"> Max </paper-item>
<paper-item label="Advantage" name="advantage"> Advantage </paper-item>
<paper-item label="Disadvantage" name="disadvantage"> Disadvantage </paper-item>
<paper-item label="PassiveAdd" name="passiveAdd"> PassiveAdd </paper-item>
<paper-item label="Fail" name="fail"> Fail </paper-item>
<paper-item label="Conditional" name="conditional"> Conditional </paper-item>
</paper-listbox>
</paper-dropdown-menu>
<paper-input class="LibraryItemEffectStat flex" label="Attribute" value={{stat}}></paper-input>
<paper-input class="LibraryItemEffectValue flex" label="Value" value={{calculationOrValue}}></paper-input>
<paper-icon-button icon="delete" class="deleteEffect"></paper-icon-button>
</div>
{{/each}}
<paper-button id="addEffect" class="red-button">Add Effect</paper-button>
</div>
<div style="margin-top: 8px;">
<div class="paper-font-subhead">Attacks</div>
{{#each indexedAttacks}}
<div class="effect layout horizontal center wrap">
<paper-input class="LibraryItemAttackBonusInput flex" label="Attack Bonus" value={{attackBonus}}></paper-input>
<paper-input class="LibraryItemAttackDamageInput flex" label="Damage" value={{damage}}></paper-input>
<paper-input class="LibraryItemAttackDetailsInput flex" label="Details" value={{details}}></paper-input>
<paper-dropdown-menu label="Damage Type" class="damageTypeMenu">
<paper-listbox class="dropdown-content" selected={{damageTypeIndex damageType}}>
<paper-item label="Bludgeoning" name="bludgeoning"> Bludgeoning </paper-item>
<paper-item label="Piercing" name="piercing"> Piercing </paper-item>
<paper-item label="Slashing" name="slashing"> Slashing </paper-item>
<paper-item label="Acid" name="acid"> Acid </paper-item>
<paper-item label="Cold" name="cold"> Cold </paper-item>
<paper-item label="Fire" name="fire"> Fire </paper-item>
<paper-item label="Force" name="force"> Force </paper-item>
<paper-item label="Lightning" name="lightning"> Lightning </paper-item>
<paper-item label="Necrotic" name="necrotic"> Necrotic </paper-item>
<paper-item label="Poison" name="poison"> Poison </paper-item>
<paper-item label="Psychic" name="psychic"> Psychic </paper-item>
<paper-item label="Radiant" name="radiant"> Radiant </paper-item>
<paper-item label="Thunder" name="thunder"> Thunder </paper-item>
</paper-listbox>
</paper-dropdown-menu>
<paper-icon-button icon="delete" class="deleteAttack"></paper-icon-button>
</div>
{{/each}}
<paper-button id="addAttack" class="red-button">Add Attack</paper-button>
</div>
</div>
</div>
</template>

View File

@@ -0,0 +1,204 @@
Template.libraryItemDialog.helpers({
item(){
return LibraryItems.findOne(this.itemId);
},
calculationOrValue(){
return this.calculation || this.value;
},
indexedEffects(){
let item = LibraryItems.findOne(this.itemId);
if (!item) return;
return _.map(item.effects, (effect, index) => {
if (!effect) return;
effect.index = index;
return effect;
});
},
indexedAttacks(){
let item = LibraryItems.findOne(this.itemId);
if (!item) return;
return _.map(item.attacks, (attack, index) => {
if (!attack) return;
attack.index = index;
return attack;
});
},
operationIndex(operation){
const ref = {
base: 0,
add: 1,
mul: 2,
min: 3,
max: 4,
advantage: 5,
disadvantage: 6,
passiveAdd: 7,
fail: 8,
conditional: 9,
};
return ref[operation];
},
damageTypeIndex(damageType){
const ref = {
bludgeoning: 0,
piercing: 1,
slashing: 2,
acid: 3,
cold: 4,
fire: 5,
force: 6,
lightning: 7,
necrotic: 8,
poison: 9,
psychic: 10,
radiant: 11,
thunder: 12,
};
return ref[damageType];
}
});
const bind = function(field){
return _.debounce(function(event){
const input = event.currentTarget;
var value = input.value;
LibraryItems.update(this.itemId, {
$set: {[field]: value}
}, {
removeEmptyStrings: false,
trimStrings: false,
});
}, 300);
};
Template.libraryItemDialog.events({
"click #backButton": function(){
popDialogStack();
},
"click #deleteButton": function(){
LibraryItems.remove(this.itemId);
popDialogStack();
},
"input #libraryItemLibraryNameInput": bind("libraryName"),
"input #libraryItemNameInput": bind("name"),
"input #libraryItemPluralInput": bind("plural"),
"input #libraryItemQuantityInput": bind("quantity"),
"input #libraryItemValueInput": bind("value"),
"input #libraryItemWeightInput": bind("weight"),
"change #attunementCheckbox": function(event){
LibraryItems.update(this.itemId, {
$set: {requiresAttunement: event.currentTarget.checked}
});
},
"change #incrementCheckbox": function(event){
LibraryItems.update(this.itemId, {
$set: {"settings.showIncrement": event.currentTarget.checked}
});
},
"input #libraryItemDescriptionInput": bind("description"),
// Effects
"click #addEffect": function(event, template){
LibraryItems.update(template.data.itemId, {
$push: {
effects: {operation: "add"}
}
});
},
"iron-select .operationMenu": function(event, template){
var detail = event.originalEvent.detail;
var opName = detail.item.getAttribute("name");
if (opName == this.operation) return;
Meteor.call("updateLibraryItemEffect", {
itemId: template.data.itemId,
effectIndex: this.index,
field: "operation",
value: opName,
});
},
"input .LibraryItemEffectStat": _.debounce(function(event, template){
Meteor.call("updateLibraryItemEffect", {
itemId: template.data.itemId,
effectIndex: this.index,
field: "stat",
value: event.currentTarget.value,
});
}, 300),
"input .LibraryItemEffectValue": _.debounce(function(event, template){
let value = event.currentTarget.value;
if (value && _.isFinite(+value)){
Meteor.call("updateLibraryItemEffect", {
itemId: template.data.itemId,
effectIndex: this.index,
field: "value",
unsetField: "calculation",
value,
});
} else {
Meteor.call("updateLibraryItemEffect", {
itemId: template.data.itemId,
effectIndex: this.index,
field: "calculation",
unsetField: "value",
value,
});
}
}, 300),
"click .deleteEffect": function (event, template) {
Meteor.call("removeLibraryItemEffect", {
itemId: template.data.itemId,
effectIndex: this.index,
});
},
// Attacks
"click #addAttack": function(event, template){
LibraryItems.update(template.data.itemId, {
$push: {
attacks: {damageType: "slashing"}
}
});
},
"iron-select .damageTypeMenu": function(event, template){
var detail = event.originalEvent.detail;
var damageType = detail.item.getAttribute("name");
if (damageType == this.damageType) return;
Meteor.call("updateLibraryItemAttack", {
itemId: template.data.itemId,
attackIndex: this.index,
field: "damageType",
value: damageType,
});
},
"input .LibraryItemAttackBonusInput": _.debounce(function(event, template){
Meteor.call("updateLibraryItemAttack", {
itemId: template.data.itemId,
attackIndex: this.index,
field: "attackBonus",
value: event.currentTarget.value,
});
}, 300),
"input .LibraryItemAttackDamageInput": _.debounce(function(event, template){
Meteor.call("updateLibraryItemAttack", {
itemId: template.data.itemId,
attackIndex: this.index,
field: "damage",
value: event.currentTarget.value,
});
}, 300),
"input .LibraryItemAttackDetailsInput": _.debounce(function(event, template){
Meteor.call("updateLibraryItemAttack", {
itemId: template.data.itemId,
attackIndex: this.index,
field: "details",
value: event.currentTarget.value,
});
}, 300),
"click .deleteAttack": function (event, template) {
Meteor.call("removeLibraryItemAttack", {
itemId: template.data.itemId,
attackIndex: this.index,
});
},
});