+
@@ -171,9 +169,7 @@
v-if="spellSlots && spellSlots.length || hasSpells"
class="spell-slots"
>
-
+
clickTreeProperty({_id})"
/>
-
diff --git a/app/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue b/app/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue
index 9c1adf87..8cc185f2 100644
--- a/app/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue
+++ b/app/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue
@@ -13,80 +13,81 @@
diff --git a/app/imports/ui/creature/creatureProperties/CreaturePropertyCreationDialog.vue b/app/imports/ui/creature/creatureProperties/CreaturePropertyCreationDialog.vue
index e24407fe..db6ceb72 100644
--- a/app/imports/ui/creature/creatureProperties/CreaturePropertyCreationDialog.vue
+++ b/app/imports/ui/creature/creatureProperties/CreaturePropertyCreationDialog.vue
@@ -20,7 +20,7 @@ import { getPropertyName } from '/imports/constants/PROPERTIES.js';
export default {
components: {
SelectablePropertyDialog,
- CreaturePropertyInsertForm,
+ CreaturePropertyInsertForm,
},
props: {
forcedType: {
@@ -28,21 +28,24 @@ export default {
default: undefined,
},
},
- data() { return {
- type: undefined,
- };},
- methods: {
- getPropertyName,
- back(){
- if (this.forcedType){
+ data() {
+ return {
+ type: undefined,
+ };
+ },
+ methods: {
+ getPropertyName,
+ back() {
+ if (this.forcedType) {
this.$store.dispatch('popDialogStack');
} else {
this.type = undefined;
}
},
- },
+ },
};
diff --git a/app/imports/ui/creature/creatureProperties/CreaturePropertyFromLibraryDialog.vue b/app/imports/ui/creature/creatureProperties/CreaturePropertyFromLibraryDialog.vue
index 1910b5ee..72d0e8da 100644
--- a/app/imports/ui/creature/creatureProperties/CreaturePropertyFromLibraryDialog.vue
+++ b/app/imports/ui/creature/creatureProperties/CreaturePropertyFromLibraryDialog.vue
@@ -23,18 +23,21 @@
diff --git a/app/imports/ui/creature/experiences/ExperienceInsertDialog.vue b/app/imports/ui/creature/experiences/ExperienceInsertDialog.vue
index 28756d1f..9b9ecc72 100644
--- a/app/imports/ui/creature/experiences/ExperienceInsertDialog.vue
+++ b/app/imports/ui/creature/experiences/ExperienceInsertDialog.vue
@@ -34,9 +34,9 @@ import schemaFormMixin from '/imports/ui/properties/forms/shared/schemaFormMixin
export default {
components: {
- DialogBase,
+ DialogBase,
ExperienceForm,
- },
+ },
mixins: [schemaFormMixin],
provide: {
context: {
@@ -52,10 +52,10 @@ export default {
type: Boolean,
},
},
- data(){
+ data() {
let schema = ExperienceSchema.omit('creatureId');
let startingModel = {};
- if (this.startAsMilestone){
+ if (this.startAsMilestone) {
startingModel.levels = 1;
}
return {
@@ -65,14 +65,14 @@ export default {
debounceTime: 0,
};
},
- methods:{
- insertExperience(){
+ methods: {
+ insertExperience() {
let experience = this.schema.clean(this.model);
let id = insertExperience.call({
experience,
creatureIds: this.creatureIds,
- }, (error) => {
- if (error){
+ }, (error) => {
+ if (error) {
console.error(error);
}
});
@@ -83,4 +83,5 @@ export default {
diff --git a/app/imports/ui/creature/slots/LevelUpDialog.vue b/app/imports/ui/creature/slots/LevelUpDialog.vue
index 7a09eb1b..4503a96e 100644
--- a/app/imports/ui/creature/slots/LevelUpDialog.vue
+++ b/app/imports/ui/creature/slots/LevelUpDialog.vue
@@ -192,18 +192,17 @@ import getSlotFillFilter from '/imports/api/creature/creatureProperties/methods/
import Libraries from '/imports/api/library/Libraries.js';
import LibraryNodeExpansionContent from '/imports/ui/library/LibraryNodeExpansionContent.vue';
import PropertyTags from '/imports/ui/properties/viewers/shared/PropertyTags.vue';
-import { getPropertyName } from '/imports/constants/PROPERTIES.js';
import { clone } from 'lodash';
export default {
components: {
- DialogBase,
+ DialogBase,
TreeNodeView,
PropertyDescription,
LibraryNodeExpansionContent,
PropertyTags,
- },
- props:{
+ },
+ props: {
classId: {
type: String,
default: undefined,
@@ -217,42 +216,44 @@ export default {
default: undefined,
},
},
- data(){return {
- selectedNodeIds: [],
- searchInput: undefined,
- searchValue: undefined,
- showDisabled: false,
- disabledNodeCount: undefined,
- }},
+ data() {
+ return {
+ selectedNodeIds: [],
+ searchInput: undefined,
+ searchValue: undefined,
+ showDisabled: false,
+ disabledNodeCount: undefined,
+ }
+ },
reactiveProvide: {
name: 'context',
include: ['creatureId'],
},
computed: {
- tagsSearched(){
+ tagsSearched() {
let or = [];
let not = [];
- if (this.model.slotTags && this.model.slotTags.length){
+ if (this.model.slotTags && this.model.slotTags.length) {
or.push(this.model.slotTags);
}
this.model.extraTags?.forEach(extras => {
- if (extras.tags?.length){
- if(extras.operation === 'OR'){
+ if (extras.tags?.length) {
+ if (extras.operation === 'OR') {
or.push(extras.tags);
- } else if (extras.operation === 'NOT'){
+ } else if (extras.operation === 'NOT') {
not.push(extras.tags);
}
}
});
- return {or, not};
+ return { or, not };
},
},
methods: {
- loadMore(){
+ loadMore() {
if (this.currentLimit >= this.countAll) return;
this._subs['classFillers'].setData('limit', this.currentLimit + 50);
},
- openPropertyDetails(id){
+ openPropertyDetails(id) {
this.$store.commit('pushDialogStack', {
component: 'library-node-dialog',
elementId: id,
@@ -261,26 +262,26 @@ export default {
},
});
},
- isDisabled(node){
+ isDisabled(node) {
return node._disabledBySlotFillerCondition ||
node._disabledByAlreadyAdded ||
- (
- node._disabledByQuantityFilled &&
- !this.selectedNodeIds.includes(node._id)
- )
+ (
+ node._disabledByQuantityFilled &&
+ !this.selectedNodeIds.includes(node._id)
+ )
},
},
meteor: {
$subscribe: {
- 'classFillers'(){
+ 'classFillers'() {
return [this.classId, this.searchValue || undefined]
},
},
- searchLoading(){
+ searchLoading() {
return !!this.searchValue && !this.$subReady.classFillers;
},
- model(){
- if (this.classId){
+ model() {
+ if (this.classId) {
return CreatureProperties.findOne(this.classId);
} else if (this.dummySlot) {
let model = clone(this.dummySlot)
@@ -294,40 +295,40 @@ export default {
if (!this.creatureId) return {};
return CreatureVariables.findOne({ _creatureId: this.creatureId }) || {};
},
- currentLimit(){
+ currentLimit() {
return this._subs['classFillers'].data('limit') || 50;
},
- countAll(){
+ countAll() {
return this._subs['classFillers'].data('countAll');
},
- alreadyAdded(){
+ alreadyAdded() {
let added = new Set();
if (!this.model.unique) return added;
let ancestorId;
- if (this.model.unique === 'uniqueInSlot'){
+ if (this.model.unique === 'uniqueInSlot') {
ancestorId = this.model._id;
- } else if (this.model.unique === 'uniqueInCreature'){
+ } else if (this.model.unique === 'uniqueInCreature') {
ancestorId = this.creatureId;
}
CreatureProperties.find({
'ancestors.id': ancestorId,
- libraryNodeId: {$exists: true},
- removed: {$ne: true},
+ libraryNodeId: { $exists: true },
+ removed: { $ne: true },
}, {
- fields: {libraryNodeId: 1},
+ fields: { libraryNodeId: 1 },
}).forEach(prop => {
added.add(prop.libraryNodeId);
});
return added;
},
- totalQuantitySelected(){
+ totalQuantitySelected() {
let quantitySelected = 0;
LibraryNodes.find({
- _id: {$in: this.selectedNodeIds}
+ _id: { $in: this.selectedNodeIds }
}, {
- fields: {slotQuantityFilled: 1},
+ fields: { slotQuantityFilled: 1 },
}).forEach(node => {
- if (Number.isFinite(node.slotQuantityFilled)){
+ if (Number.isFinite(node.slotQuantityFilled)) {
quantitySelected += node.slotQuantityFilled;
} else {
quantitySelected += 1;
@@ -335,30 +336,30 @@ export default {
});
return quantitySelected;
},
- spaceLeft(){
+ spaceLeft() {
if (!this.model.quantityExpected || this.model.quantityExpected.value === 0) return undefined;
return this.model.spaceLeft - this.totalQuantitySelected;
},
- libraryNames(){
+ libraryNames() {
let names = {};
Libraries.find().forEach(lib => names[lib._id] = lib.name)
return names;
},
- libraryNodes(){
+ libraryNodes() {
let filter = getSlotFillFilter({ slot: this.model });
let nodes = LibraryNodes.find(filter, {
- sort: {name: 1, order: 1}
+ sort: { name: 1, order: 1 }
}).fetch();
let disabledNodeCount = 0;
// Mark classFillers whose condition isn't met or are too big to fit
// the quantity to fill
nodes.forEach(node => {
- if (node.slotFillerCondition){
+ if (node.slotFillerCondition) {
try {
let parseNode = parse(node.slotFillerCondition);
- const {result: resultNode} = resolve('reduce', parseNode, this.variables);
- if (resultNode?.parseType === 'constant'){
- if (!resultNode.value){
+ const { result: resultNode } = resolve('reduce', parseNode, this.variables);
+ if (resultNode?.parseType === 'constant') {
+ if (!resultNode.value) {
node._disabledBySlotFillerCondition = true;
disabledNodeCount += 1;
}
@@ -367,7 +368,7 @@ export default {
node._conditionError = toString(resultNode);
disabledNodeCount += 1;
}
- } catch (e){
+ } catch (e) {
console.warn(e);
let error = prettifyParseError(e);
node._disabledBySlotFillerCondition = true;
@@ -378,10 +379,10 @@ export default {
let quantityToFill = node.type === 'slotFiller' ? node.slotQuantityFilled : 1;
if (
quantityToFill > this.spaceLeft
- ){
+ ) {
node._disabledByQuantityFilled = true;
}
- if (this.alreadyAdded.has(node._id)){
+ if (this.alreadyAdded.has(node._id)) {
node._disabledByAlreadyAdded = true;
}
});
@@ -393,7 +394,7 @@ export default {
diff --git a/app/imports/ui/creature/slots/SlotCard.vue b/app/imports/ui/creature/slots/SlotCard.vue
index 73c52813..44f6ab76 100644
--- a/app/imports/ui/creature/slots/SlotCard.vue
+++ b/app/imports/ui/creature/slots/SlotCard.vue
@@ -62,8 +62,10 @@ export default {
hover: false,
}},
computed: {
- accentColor(){
- if (this.theme.isDark){
+ accentColor() {
+ if (this.model.color) {
+ return this.model.color
+ } else if (this.theme.isDark){
return this.$vuetify.theme.themes.dark.primary;
} else {
return this.$vuetify.theme.themes.light.primary;
diff --git a/app/imports/ui/creature/slots/SlotCardsToFill.vue b/app/imports/ui/creature/slots/SlotCardsToFill.vue
index 2c2d873c..043489e7 100644
--- a/app/imports/ui/creature/slots/SlotCardsToFill.vue
+++ b/app/imports/ui/creature/slots/SlotCardsToFill.vue
@@ -5,6 +5,18 @@
leave-absolute
hide-on-leave
>
+
@@ -24,6 +36,7 @@
diff --git a/app/imports/ui/creature/slots/SlotFillDialog.vue b/app/imports/ui/creature/slots/SlotFillDialog.vue
index caee497e..cbad8fb9 100644
--- a/app/imports/ui/creature/slots/SlotFillDialog.vue
+++ b/app/imports/ui/creature/slots/SlotFillDialog.vue
@@ -198,13 +198,13 @@ import { clone } from 'lodash';
export default {
components: {
- DialogBase,
+ DialogBase,
TreeNodeView,
PropertyDescription,
LibraryNodeExpansionContent,
PropertyTags,
- },
- props:{
+ },
+ props: {
slotId: {
type: String,
default: undefined,
@@ -218,36 +218,38 @@ export default {
default: undefined,
},
},
- data(){return {
- selectedNodeIds: [],
- searchInput: undefined,
- searchValue: undefined,
- showDisabled: false,
- disabledNodeCount: undefined,
- }},
+ data() {
+ return {
+ selectedNodeIds: [],
+ searchInput: undefined,
+ searchValue: undefined,
+ showDisabled: false,
+ disabledNodeCount: undefined,
+ }
+ },
reactiveProvide: {
name: 'context',
include: ['creatureId'],
},
computed: {
- tagsSearched(){
+ tagsSearched() {
let or = [];
let not = [];
- if (this.model.slotTags && this.model.slotTags.length){
+ if (this.model.slotTags && this.model.slotTags.length) {
or.push(this.model.slotTags);
}
this.model.extraTags?.forEach(extras => {
- if (extras.tags?.length){
- if(extras.operation === 'OR'){
+ if (extras.tags?.length) {
+ if (extras.operation === 'OR') {
or.push(extras.tags);
- } else if (extras.operation === 'NOT'){
+ } else if (extras.operation === 'NOT') {
not.push(extras.tags);
}
}
});
- return {or, not};
+ return { or, not };
},
- slotPropertyTypeName(){
+ slotPropertyTypeName() {
if (!this.model) return;
if (!this.model.slotType) return 'Property';
let propName = getPropertyName(this.model.slotType);
@@ -255,11 +257,11 @@ export default {
},
},
methods: {
- loadMore(){
+ loadMore() {
if (this.currentLimit >= this.countAll) return;
this._subs['slotFillers'].setData('limit', this.currentLimit + 50);
},
- openPropertyDetails(id){
+ openPropertyDetails(id) {
this.$store.commit('pushDialogStack', {
component: 'library-node-dialog',
elementId: id,
@@ -268,26 +270,26 @@ export default {
},
});
},
- isDisabled(node){
+ isDisabled(node) {
return node._disabledBySlotFillerCondition ||
node._disabledByAlreadyAdded ||
- (
- node._disabledByQuantityFilled &&
- !this.selectedNodeIds.includes(node._id)
- )
+ (
+ node._disabledByQuantityFilled &&
+ !this.selectedNodeIds.includes(node._id)
+ )
},
},
meteor: {
$subscribe: {
- 'slotFillers'(){
+ 'slotFillers'() {
return [this.slotId, this.searchValue || undefined]
},
},
- searchLoading(){
+ searchLoading() {
return !!this.searchValue && !this.$subReady.slotFillers;
},
- model(){
- if (this.slotId){
+ model() {
+ if (this.slotId) {
return CreatureProperties.findOne(this.slotId);
} else if (this.dummySlot) {
let model = clone(this.dummySlot)
@@ -301,40 +303,40 @@ export default {
if (!this.creatureId) return {};
return CreatureVariables.findOne({ _creatureId: this.creatureId }) || {};
},
- currentLimit(){
+ currentLimit() {
return this._subs['slotFillers'].data('limit') || 50;
},
- countAll(){
+ countAll() {
return this._subs['slotFillers'].data('countAll');
},
- alreadyAdded(){
+ alreadyAdded() {
let added = new Set();
if (!this.model.unique) return added;
let ancestorId;
- if (this.model.unique === 'uniqueInSlot'){
+ if (this.model.unique === 'uniqueInSlot') {
ancestorId = this.model._id;
- } else if (this.model.unique === 'uniqueInCreature'){
+ } else if (this.model.unique === 'uniqueInCreature') {
ancestorId = this.creatureId;
}
CreatureProperties.find({
'ancestors.id': ancestorId,
- libraryNodeId: {$exists: true},
- removed: {$ne: true},
+ libraryNodeId: { $exists: true },
+ removed: { $ne: true },
}, {
- fields: {libraryNodeId: 1},
+ fields: { libraryNodeId: 1 },
}).forEach(prop => {
added.add(prop.libraryNodeId);
});
return added;
},
- totalQuantitySelected(){
+ totalQuantitySelected() {
let quantitySelected = 0;
LibraryNodes.find({
- _id: {$in: this.selectedNodeIds}
+ _id: { $in: this.selectedNodeIds }
}, {
- fields: {slotQuantityFilled: 1},
+ fields: { slotQuantityFilled: 1 },
}).forEach(node => {
- if (Number.isFinite(node.slotQuantityFilled)){
+ if (Number.isFinite(node.slotQuantityFilled)) {
quantitySelected += node.slotQuantityFilled;
} else {
quantitySelected += 1;
@@ -342,30 +344,30 @@ export default {
});
return quantitySelected;
},
- spaceLeft(){
+ spaceLeft() {
if (!this.model.quantityExpected || this.model.quantityExpected.value === 0) return undefined;
return this.model.spaceLeft - this.totalQuantitySelected;
},
- libraryNames(){
+ libraryNames() {
let names = {};
Libraries.find().forEach(lib => names[lib._id] = lib.name)
return names;
},
- libraryNodes(){
- let filter = getSlotFillFilter({slot: this.model});
+ libraryNodes() {
+ let filter = getSlotFillFilter({ slot: this.model });
let nodes = LibraryNodes.find(filter, {
- sort: {name: 1, order: 1}
+ sort: { name: 1, order: 1 }
}).fetch();
let disabledNodeCount = 0;
// Mark slotFillers whose condition isn't met or are too big to fit
// the quantity to fill
nodes.forEach(node => {
- if (node.slotFillerCondition){
+ if (node.slotFillerCondition) {
try {
let parseNode = parse(node.slotFillerCondition);
- const {result: resultNode} = resolve('reduce', parseNode, this.variables);
- if (resultNode?.parseType === 'constant'){
- if (!resultNode.value){
+ const { result: resultNode } = resolve('reduce', parseNode, this.variables);
+ if (resultNode?.parseType === 'constant') {
+ if (!resultNode.value) {
node._disabledBySlotFillerCondition = true;
disabledNodeCount += 1;
}
@@ -374,7 +376,7 @@ export default {
node._conditionError = toString(resultNode);
disabledNodeCount += 1;
}
- } catch (e){
+ } catch (e) {
console.warn(e);
let error = prettifyParseError(e);
node._disabledBySlotFillerCondition = true;
@@ -385,10 +387,10 @@ export default {
let quantityToFill = node.type === 'slotFiller' ? node.slotQuantityFilled : 1;
if (
quantityToFill > this.spaceLeft
- ){
+ ) {
node._disabledByQuantityFilled = true;
}
- if (this.alreadyAdded.has(node._id)){
+ if (this.alreadyAdded.has(node._id)) {
node._disabledByAlreadyAdded = true;
}
});
@@ -400,7 +402,7 @@ export default {
diff --git a/app/imports/ui/dialogStack/DeleteConfirmationDialog.vue b/app/imports/ui/dialogStack/DeleteConfirmationDialog.vue
index d7f90460..c8b76735 100644
--- a/app/imports/ui/dialogStack/DeleteConfirmationDialog.vue
+++ b/app/imports/ui/dialogStack/DeleteConfirmationDialog.vue
@@ -4,7 +4,10 @@
Delete {{ typeName }}
-
+
This can't be undone
@@ -12,9 +15,9 @@
diff --git a/app/imports/ui/dialogStack/DialogBase.vue b/app/imports/ui/dialogStack/DialogBase.vue
index 14a1f1cf..4fcdd912 100644
--- a/app/imports/ui/dialogStack/DialogBase.vue
+++ b/app/imports/ui/dialogStack/DialogBase.vue
@@ -50,63 +50,69 @@
diff --git a/app/imports/ui/dialogStack/DialogComponentIndex.js b/app/imports/ui/dialogStack/DialogComponentIndex.js
index c8079709..ef89fc6a 100644
--- a/app/imports/ui/dialogStack/DialogComponentIndex.js
+++ b/app/imports/ui/dialogStack/DialogComponentIndex.js
@@ -1,18 +1,26 @@
-const AddCreaturePropertyDialog = () => import('/imports/ui/creature/creatureProperties/AddCreaturePropertyDialog.vue');
+// Load commonly used dialogs immediately
+import AddCreaturePropertyDialog from '/imports/ui/creature/creatureProperties/AddCreaturePropertyDialog.vue';
+import CharacterCreationDialog from '/imports/ui/creature/character/CharacterCreationDialog.vue';
+import CastSpellWithSlotDialog from '/imports/ui/properties/components/spells/CastSpellWithSlotDialog.vue';
+import CreatureFormDialog from '/imports/ui/creature/CreatureFormDialog.vue';
+import CreaturePropertyCreationDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyCreationDialog.vue';
+import CreaturePropertyDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyDialog.vue';
+import CreaturePropertyFromLibraryDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyFromLibraryDialog.vue';
+import CreatureRootDialog from '/imports/ui/creature/character/CreatureRootDialog.vue';
+import DeleteConfirmationDialog from '/imports/ui/dialogStack/DeleteConfirmationDialog.vue';
+import ExperienceInsertDialog from '/imports/ui/creature/experiences/ExperienceInsertDialog.vue';
+import ExperienceListDialog from '/imports/ui/creature/experiences/ExperienceListDialog.vue';
+import HelpDialog from '/imports/ui/dialogStack/HelpDialog.vue';
+import LevelUpDialog from '/imports/ui/creature/slots/LevelUpDialog.vue';
+import SelectLibraryNodeDialog from '/imports/ui/library/SelectLibraryNodeDialog.vue';
+import SlotFillDialog from '/imports/ui/creature/slots/SlotFillDialog.vue';
+import TierTooLowDialog from '/imports/ui/user/TierTooLowDialog.vue';
+import TransferOwnershipDialog from '/imports/ui/sharing/TransferOwnershipDialog.vue';
+
+// Lazily load less common dialogs
const ArchiveDialog = () => import('/imports/ui/creature/archive/ArchiveDialog.vue');
-const CharacterCreationDialog = () => import('/imports/ui/creature/character/CharacterCreationDialog.vue');
-const CastSpellWithSlotDialog = () => import('/imports/ui/properties/components/spells/CastSpellWithSlotDialog.vue');
-const CreatureFormDialog = () => import('/imports/ui/creature/CreatureFormDialog.vue');
-const CreaturePropertyCreationDialog = () => import('/imports/ui/creature/creatureProperties/CreaturePropertyCreationDialog.vue');
-const CreaturePropertyDialog = () => import('/imports/ui/creature/creatureProperties/CreaturePropertyDialog.vue');
-const CreaturePropertyFromLibraryDialog = () => import('/imports/ui/creature/creatureProperties/CreaturePropertyFromLibraryDialog.vue');
-const CreatureRootDialog = () => import('/imports/ui/creature/character/CreatureRootDialog.vue');
-const DeleteConfirmationDialog = () => import('/imports/ui/dialogStack/DeleteConfirmationDialog.vue');
const DeleteUserAccountDialog = () => import('/imports/ui/user/DeleteUserAccountDialog.vue');
-const ExperienceInsertDialog = () => import( '/imports/ui/creature/experiences/ExperienceInsertDialog.vue');
-const ExperienceListDialog = () => import( '/imports/ui/creature/experiences/ExperienceListDialog.vue');
const InviteDialog = () => import('/imports/ui/user/InviteDialog.vue');
-const LevelUpDialog = () => import('/imports/ui/creature/slots/LevelUpDialog.vue');
const LibraryCollectionCreationDialog = () => import('/imports/ui/library/LibraryCollectionCreationDialog.vue');
const LibraryCollectionEditDialog = () => import('/imports/ui/library/LibraryCollectionEditDialog.vue');
const LibraryCreationDialog = () => import('/imports/ui/library/LibraryCreationDialog.vue');
@@ -21,11 +29,7 @@ const LibraryNodeCreationDialog = () => import('/imports/ui/library/LibraryNodeC
const LibraryNodeDialog = () => import('/imports/ui/library/LibraryNodeDialog.vue');
const MoveLibraryNodeDialog = () => import('/imports/ui/library/MoveLibraryNodeDialog.vue');
const SelectCreaturesDialog = () => import('/imports/ui/tabletop/SelectCreaturesDialog.vue');
-const SelectLibraryNodeDialog = () => import('/imports/ui/library/SelectLibraryNodeDialog.vue');
const ShareDialog = () => import('/imports/ui/sharing/ShareDialog.vue');
-const SlotFillDialog = () => import('/imports/ui/creature/slots/SlotFillDialog.vue');
-const TierTooLowDialog = () => import('/imports/ui/user/TierTooLowDialog.vue');
-const TransferOwnershipDialog = () => import('/imports/ui/sharing/TransferOwnershipDialog.vue');
const UsernameDialog = () => import('/imports/ui/user/UsernameDialog.vue');
export default {
@@ -42,6 +46,7 @@ export default {
DeleteUserAccountDialog,
ExperienceInsertDialog,
ExperienceListDialog,
+ HelpDialog,
InviteDialog,
LevelUpDialog,
LibraryCollectionCreationDialog,
diff --git a/app/imports/ui/dialogStack/HelpDialog.vue b/app/imports/ui/dialogStack/HelpDialog.vue
new file mode 100644
index 00000000..9fe700b2
--- /dev/null
+++ b/app/imports/ui/dialogStack/HelpDialog.vue
@@ -0,0 +1,108 @@
+
+
+
+ mdi-help
+
+
+ Help: {{ title }}
+
+
+
+
+ Help document not found for {{ title }}
+
+
+
+
+
+ Close
+
+
+
+
+
+
+
diff --git a/app/imports/ui/dialogStack/mockElement.js b/app/imports/ui/dialogStack/mockElement.js
index de843514..6f179af5 100644
--- a/app/imports/ui/dialogStack/mockElement.js
+++ b/app/imports/ui/dialogStack/mockElement.js
@@ -2,42 +2,42 @@ import { parse, stringify } from 'css-box-shadow';
// Only supports border radius defined like "20px" or "100%"
const transformedRadius = (radiusString, deltaWidth, deltaHeight) => {
- if (/^\d+\.?\d*px$/.test(radiusString)){
- //The radius is defined in pixel units, so get the radius as a number
- const rad = +radiusString.match(/\d+\.?\d*/)[0];
- // Set the x and y radius of the "to" element, compensating for scale
- return `${rad / deltaWidth}px / ${rad / deltaHeight}px`;
- } else if (/^\d+\.?\d*%$/.test(radiusString)) {
- //The radius is defined as a percentage, so just use it as is
- return radiusString;
- }
+ if (/^\d+\.?\d*px$/.test(radiusString)) {
+ //The radius is defined in pixel units, so get the radius as a number
+ const rad = +radiusString.match(/\d+\.?\d*/)[0];
+ // Set the x and y radius of the "to" element, compensating for scale
+ return `${rad / deltaWidth}px / ${rad / deltaHeight}px`;
+ } else if (/^\d+\.?\d*%$/.test(radiusString)) {
+ //The radius is defined as a percentage, so just use it as is
+ return radiusString;
+ }
};
const transformedBoxShadow = (shadowString, deltaWidth, deltaHeight) => {
- if (shadowString === 'none') return shadowString;
- if (shadowString[0] === 'r'){
- let strings = shadowString.match(/rgba\([^)]+\)[^,]+/g);
- strings = strings.map(string => {
- // Move color to end
- let m = string.match(/(rgba\([^)]+\))([^,]+)/);
- return `${m[2].trim()} ${m[1]}`;
- });
- shadowString = strings.join(', ');
- }
- let scaleAverage = (deltaWidth + deltaHeight) / 2;
- let shadows = parse(shadowString);
- shadows.forEach(shadow => {
- shadow.offsetX /= deltaWidth;
- shadow.offsetY /= deltaHeight;
- shadow.blurRadius /= scaleAverage;
- shadow.spreadRadius /= scaleAverage;
- })
- return stringify(shadows);
+ if (shadowString === 'none') return shadowString;
+ if (shadowString[0] === 'r') {
+ let strings = shadowString.match(/rgba\([^)]+\)[^,]+/g);
+ strings = strings.map(string => {
+ // Move color to end
+ let m = string.match(/(rgba\([^)]+\))([^,]+)/);
+ return `${m[2].trim()} ${m[1]}`;
+ });
+ shadowString = strings.join(', ');
+ }
+ let scaleAverage = (deltaWidth + deltaHeight) / 2;
+ let shadows = parse(shadowString);
+ shadows.forEach(shadow => {
+ shadow.offsetX /= deltaWidth;
+ shadow.offsetY /= deltaHeight;
+ shadow.blurRadius /= scaleAverage;
+ shadow.spreadRadius /= scaleAverage;
+ })
+ return stringify(shadows);
}
-export default function mockElement({source, target, offset = {x: 0, y: 0}}){
- if (!source || !target) throw `Can't mock without ${source ? 'target' : 'source'}` ;
- let sourceRect = source.getBoundingClientRect();
+export default function mockElement({ source, target, offset = { x: 0, y: 0 } }) {
+ if (!source || !target) throw `Can't mock without ${source ? 'target' : 'source'}`;
+ let sourceRect = source.getBoundingClientRect();
let targetRect = target.getBoundingClientRect();
// Get how must the target change to become the source
@@ -47,20 +47,20 @@ export default function mockElement({source, target, offset = {x: 0, y: 0}}){
const deltaTop = sourceRect.top - targetRect.top + offset.y;
// Mock the source
target.style.transform = `translate(${deltaLeft}px, ${deltaTop}px) ` +
- `scale(${deltaWidth}, ${deltaHeight})`;
+ `scale(${deltaWidth}, ${deltaHeight})`;
// Mock the background color unless it's completely transparent
let backgroundColor = getComputedStyle(source).backgroundColor
- if (backgroundColor !== 'rgba(0, 0, 0, 0)'){
+ if (backgroundColor !== 'rgba(0, 0, 0, 0)') {
target.style.backgroundColor = backgroundColor;
}
- // Edge might not combine all border radii into a single value,
- // So we just sample the top left one if we need to
- let oldRadius = getComputedStyle(source).borderRadius ||
- getComputedStyle(source).borderTopLeftRadius;
- let borderRadius = transformedRadius(oldRadius, deltaWidth, deltaHeight);
- target.style.borderRadius = borderRadius;
- let boxShadow = transformedBoxShadow(
- getComputedStyle(source).boxShadow, deltaWidth, deltaHeight
- );
- target.style.setProperty('box-shadow', boxShadow, 'important');
+ // Edge might not combine all border radii into a single value,
+ // So we just sample the top left one if we need to
+ let oldRadius = getComputedStyle(source).borderRadius ||
+ getComputedStyle(source).borderTopLeftRadius;
+ let borderRadius = transformedRadius(oldRadius, deltaWidth, deltaHeight);
+ target.style.borderRadius = borderRadius;
+ let boxShadow = transformedBoxShadow(
+ getComputedStyle(source).boxShadow, deltaWidth, deltaHeight
+ );
+ target.style.setProperty('box-shadow', boxShadow, 'important');
}
diff --git a/app/imports/ui/documentation/FunctionReference.vue b/app/imports/ui/documentation/FunctionReference.vue
deleted file mode 100644
index b8172fbd..00000000
--- a/app/imports/ui/documentation/FunctionReference.vue
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
{{ fn.name }}
-
- {{ fn.comment }}
-
-
-
-
- {{ example.input }}
- |
-
- mdi-arrow-right-thick
- |
-
- {{ example.result }}
- |
-
-
-
-
-
-
-
-
-
diff --git a/app/imports/ui/files/ArchiveFileCard.vue b/app/imports/ui/files/ArchiveFileCard.vue
index cab9edde..d8ec1f25 100644
--- a/app/imports/ui/files/ArchiveFileCard.vue
+++ b/app/imports/ui/files/ArchiveFileCard.vue
@@ -44,17 +44,19 @@ export default {
required: true,
},
},
- data(){return {
- restoreLoading: false,
- removeLoading: false,
- }},
- meteor: {
- characterSlots(){
+ data() {
+ return {
+ restoreLoading: false,
+ removeLoading: false,
+ }
+ },
+ meteor: {
+ characterSlots() {
return characterSlotsRemaining(Meteor.userId());
},
- },
+ },
methods: {
- restore(){
+ restore() {
this.restoreLoading = true;
restoreCreatureFromFile.call({
fileId: this.model._id,
@@ -62,26 +64,26 @@ export default {
this.restoreLoading = false;
if (!error) return;
console.error(error);
- snackbar({text: error.reason});
+ snackbar({ text: error.reason });
+ });
+ },
+ removeArchiveCharacter() {
+ let that = this;
+ this.$store.commit('pushDialogStack', {
+ component: 'delete-confirmation-dialog',
+ elementId: `${that.model._id}-archive-card`,
+ data: {
+ name: this.model.meta.creatureName,
+ typeName: 'Character Archive'
+ },
+ callback(confirmation) {
+ if (!confirmation) return;
+ removeArchiveCreature.call({ fileId: that.model._id }, (error) => {
+ if (error) console.error(error);
+ });
+ }
});
},
- removeArchiveCharacter(){
- let that = this;
- this.$store.commit('pushDialogStack', {
- component: 'delete-confirmation-dialog',
- elementId: `${that.model._id}-archive-card`,
- data: {
- name: this.model.meta.creatureName,
- typeName: 'Character Archive'
- },
- callback(confirmation){
- if(!confirmation) return;
- removeArchiveCreature.call({fileId: that.model._id}, (error) => {
- if (error) console.error(error);
- });
- }
- });
- },
},
}
diff --git a/app/imports/ui/files/UserImageCard.vue b/app/imports/ui/files/UserImageCard.vue
index e70141a6..85c5d155 100644
--- a/app/imports/ui/files/UserImageCard.vue
+++ b/app/imports/ui/files/UserImageCard.vue
@@ -34,7 +34,6 @@
diff --git a/app/imports/ui/layouts/AppLayout.vue b/app/imports/ui/layouts/AppLayout.vue
index 8d958e86..99469969 100644
--- a/app/imports/ui/layouts/AppLayout.vue
+++ b/app/imports/ui/layouts/AppLayout.vue
@@ -6,9 +6,7 @@
>
-
+
-
+
{{ $store.state.pageTitle }}
-
+
-
+
-
+
-
+
-
+
diff --git a/app/imports/ui/layouts/Sidebar.vue b/app/imports/ui/layouts/Sidebar.vue
index 9c050890..31b5fa60 100644
--- a/app/imports/ui/layouts/Sidebar.vue
+++ b/app/imports/ui/layouts/Sidebar.vue
@@ -99,6 +99,7 @@
{title: 'Files', icon: 'mdi-file-multiple', to: '/my-files'},
{title: 'Feedback', icon: 'mdi-bug', to: '/feedback'},
{title: 'About', icon: 'mdi-sign-text', to: '/about'},
+ {title: 'Documentation', icon: 'mdi-book-open-variant', to: '/docs'},
{title: 'Patreon', icon: 'mdi-patreon', href: 'https://www.patreon.com/dicecloud'},
{title: 'Github', icon: 'mdi-github', href: 'https://github.com/ThaumRystra/DiceCloud/tree/version-2'},
];
diff --git a/app/imports/ui/library/LibraryCollectionEditDialog.vue b/app/imports/ui/library/LibraryCollectionEditDialog.vue
index 8cf2e70c..cccce61a 100644
--- a/app/imports/ui/library/LibraryCollectionEditDialog.vue
+++ b/app/imports/ui/library/LibraryCollectionEditDialog.vue
@@ -63,62 +63,62 @@ import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
import Libraries from '/imports/api/library/Libraries.js';
export default {
- components: {
- DialogBase,
- },
- props: {
- _id: String,
- },
- methods: {
- updateLibraryCollection(update, ack){
- updateLibraryCollection.call({_id: this._id, update}, (error) =>{
- ack(error && error.reason || error);
- });
+ components: {
+ DialogBase,
+ },
+ props: {
+ _id: String,
+ },
+ methods: {
+ updateLibraryCollection(update, ack) {
+ updateLibraryCollection.call({ _id: this._id, update }, (error) => {
+ ack(error && error.reason || error);
+ });
},
- remove(){
- let that = this;
- this.$store.commit('pushDialogStack', {
- component: 'delete-confirmation-dialog',
- elementId: 'delete-library-button',
- data: {
- name: this.model.name,
- typeName: 'Collection'
- },
- callback(confirmation){
- if(!confirmation) return;
- removeLibraryCollection.call({_id: that._id}, (error) => {
+ remove() {
+ let that = this;
+ this.$store.commit('pushDialogStack', {
+ component: 'delete-confirmation-dialog',
+ elementId: 'delete-library-button',
+ data: {
+ name: this.model.name,
+ typeName: 'Collection'
+ },
+ callback(confirmation) {
+ if (!confirmation) return;
+ removeLibraryCollection.call({ _id: that._id }, (error) => {
if (error) {
console.error(error);
snackbar({
text: error.reason,
});
- } else {
+ } else {
that.$router.push({ name: 'library', replace: true });
that.$store.dispatch('popDialogStack');
- }
- });
- }
- });
- },
- share(){
- this.$store.commit('pushDialogStack', {
- component: 'share-dialog',
- elementId: 'share-library-button',
- data: {
- docRef: {
+ }
+ });
+ }
+ });
+ },
+ share() {
+ this.$store.commit('pushDialogStack', {
+ component: 'share-dialog',
+ elementId: 'share-library-button',
+ data: {
+ docRef: {
id: this._id,
collection: 'libraryCollections',
}
- },
- });
- },
- },
- meteor: {
- '$subscribe':{
+ },
+ });
+ },
+ },
+ meteor: {
+ '$subscribe': {
libraries: [],
},
- model(){
- return LibraryCollections.findOne(this._id);
+ model() {
+ return LibraryCollections.findOne(this._id);
},
libraryOptions() {
const userId = Meteor.userId();
@@ -131,7 +131,7 @@ export default {
{ public: true },
]
},
- {sort: {name: 1}}
+ { sort: { name: 1 } }
).map(library => {
return {
text: library.name,
@@ -139,9 +139,10 @@ export default {
};
});
},
- }
+ }
}
diff --git a/app/imports/ui/library/LibraryCollectionToolbar.vue b/app/imports/ui/library/LibraryCollectionToolbar.vue
index 4147836e..0a128b90 100644
--- a/app/imports/ui/library/LibraryCollectionToolbar.vue
+++ b/app/imports/ui/library/LibraryCollectionToolbar.vue
@@ -43,24 +43,26 @@ import { assertDocEditPermission } from '/imports/api/sharing/sharingPermissions
import { mapMutations } from 'vuex';
export default {
- data(){ return {
- loading: false,
- }},
+ data() {
+ return {
+ loading: false,
+ }
+ },
meteor: {
- libraryCollection(){
+ libraryCollection() {
return LibraryCollections.findOne(this.$route.params.id);
},
- subscribed(){
+ subscribed() {
const libraryCollectionId = this.$route.params.id;
const user = Meteor.user();
return user?.subscribedLibraryCollections?.includes(libraryCollectionId);
},
- showSubscribeButton(){
+ showSubscribeButton() {
let user = Meteor.user();
let libraryCollection = this.libraryCollection;
if (!user || !libraryCollection) return;
let userId = user._id;
- if (user.subscribedLibraryCollections?.includes(libraryCollection._id)){
+ if (user.subscribedLibraryCollections?.includes(libraryCollection._id)) {
return true
} else if (
libraryCollection.readers.includes(userId) ||
@@ -72,7 +74,7 @@ export default {
return true;
}
},
- canEdit(){
+ canEdit() {
try {
assertDocEditPermission(this.libraryCollection, Meteor.userId());
return true
@@ -85,7 +87,7 @@ export default {
...mapMutations([
'toggleDrawer',
]),
- subscribe(value){
+ subscribe(value) {
this.loading = true;
Meteor.users.subscribeToLibraryCollection.call({
libraryCollectionId: this.$route.params.id,
@@ -94,16 +96,17 @@ export default {
this.loading = false;
});
},
- editLibraryCollection(){
- this.$store.commit('pushDialogStack', {
- component: 'library-collection-edit-dialog',
- elementId: 'library-collection-edit-button',
- data: {_id: this.$route.params.id},
- });
- },
+ editLibraryCollection() {
+ this.$store.commit('pushDialogStack', {
+ component: 'library-collection-edit-dialog',
+ elementId: 'library-collection-edit-button',
+ data: { _id: this.$route.params.id },
+ });
+ },
},
}
diff --git a/app/imports/ui/library/LibraryContentsContainer.vue b/app/imports/ui/library/LibraryContentsContainer.vue
index f30e30fb..1e70fa07 100644
--- a/app/imports/ui/library/LibraryContentsContainer.vue
+++ b/app/imports/ui/library/LibraryContentsContainer.vue
@@ -1,7 +1,5 @@
-
+
diff --git a/app/imports/ui/library/LibraryCreationDialog.vue b/app/imports/ui/library/LibraryCreationDialog.vue
index 55f6894d..fe71d5fa 100644
--- a/app/imports/ui/library/LibraryCreationDialog.vue
+++ b/app/imports/ui/library/LibraryCreationDialog.vue
@@ -5,20 +5,18 @@
New Library
-
-
-
-
+
+
diff --git a/app/imports/ui/library/LibraryEditDialog.vue b/app/imports/ui/library/LibraryEditDialog.vue
index 2b08a9ae..6586b649 100644
--- a/app/imports/ui/library/LibraryEditDialog.vue
+++ b/app/imports/ui/library/LibraryEditDialog.vue
@@ -82,86 +82,87 @@ import TreeNodeView from '/imports/ui/properties/treeNodeViews/TreeNodeView.vue'
import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
export default {
- components: {
- DialogBase,
+ components: {
+ DialogBase,
TreeNodeView,
- },
- props: {
- _id: String,
- },
- methods: {
- updateName(value, ack){
- updateLibraryName.call({_id: this._id, name: value}, (error) =>{
- ack(error && error.reason || error);
- });
+ },
+ props: {
+ _id: String,
+ },
+ methods: {
+ updateName(value, ack) {
+ updateLibraryName.call({ _id: this._id, name: value }, (error) => {
+ ack(error && error.reason || error);
+ });
},
- updateDescription(value, ack){
- updateLibraryDescription.call({_id: this._id, description: value}, (error) =>{
- ack(error && error.reason || error);
- });
+ updateDescription(value, ack) {
+ updateLibraryDescription.call({ _id: this._id, description: value }, (error) => {
+ ack(error && error.reason || error);
+ });
},
- remove(){
- let that = this;
- this.$store.commit('pushDialogStack', {
- component: 'delete-confirmation-dialog',
- elementId: 'delete-library-button',
- data: {
- name: this.model.name,
- typeName: 'Library'
- },
- callback(confirmation){
- if(!confirmation) return;
- removeLibrary.call({_id: that._id}, (error) => {
+ remove() {
+ let that = this;
+ this.$store.commit('pushDialogStack', {
+ component: 'delete-confirmation-dialog',
+ elementId: 'delete-library-button',
+ data: {
+ name: this.model.name,
+ typeName: 'Library'
+ },
+ callback(confirmation) {
+ if (!confirmation) return;
+ removeLibrary.call({ _id: that._id }, (error) => {
if (error) {
console.error(error);
snackbar({
text: error.reason,
});
- } else {
+ } else {
that.$router.push({ name: 'library', replace: true });
that.$store.dispatch('popDialogStack');
- }
- });
- }
- });
- },
- share(){
- this.$store.commit('pushDialogStack', {
- component: 'share-dialog',
- elementId: 'share-library-button',
- data: {
- docRef: {
+ }
+ });
+ }
+ });
+ },
+ share() {
+ this.$store.commit('pushDialogStack', {
+ component: 'share-dialog',
+ elementId: 'share-library-button',
+ data: {
+ docRef: {
id: this._id,
collection: 'libraries',
}
- },
- });
- },
- restore(_id){
- restoreLibraryNode.call({_id});
+ },
+ });
},
- },
- meteor: {
- '$subscribe':{
- softRemovedLibraryNodes(){
+ restore(_id) {
+ restoreLibraryNode.call({ _id });
+ },
+ },
+ meteor: {
+ '$subscribe': {
+ softRemovedLibraryNodes() {
return [this._id];
},
},
- model(){
- return Libraries.findOne(this._id);
- },
- removedDocs(){
+ model() {
+ return Libraries.findOne(this._id);
+ },
+ removedDocs() {
return LibraryNodes.find({
'ancestors.0.id': this._id,
removed: true,
- removedWith: {$exists: false},
+ removedWith: { $exists: false },
}, {
- sort: {order: 1},
+ sort: { order: 1 },
});
}
- }
+ }
}
diff --git a/app/imports/ui/library/LibraryNodeCreationDialog.vue b/app/imports/ui/library/LibraryNodeCreationDialog.vue
index e1a46b41..2f4ff67d 100644
--- a/app/imports/ui/library/LibraryNodeCreationDialog.vue
+++ b/app/imports/ui/library/LibraryNodeCreationDialog.vue
@@ -16,16 +16,19 @@ import { getPropertyName } from '/imports/constants/PROPERTIES.js';
export default {
components: {
SelectablePropertyDialog,
- LibraryNodeInsertForm,
+ LibraryNodeInsertForm,
+ },
+ data() {
+ return {
+ type: undefined,
+ };
+ },
+ methods: {
+ getPropertyName,
},
- data() { return {
- type: undefined,
- };},
- methods: {
- getPropertyName,
- },
};
diff --git a/app/imports/ui/library/LibraryNodeInsertForm.vue b/app/imports/ui/library/LibraryNodeInsertForm.vue
index 8e8b8c2f..ebd94d49 100644
--- a/app/imports/ui/library/LibraryNodeInsertForm.vue
+++ b/app/imports/ui/library/LibraryNodeInsertForm.vue
@@ -46,41 +46,50 @@ import ColorPicker from '/imports/ui/components/ColorPicker.vue';
import propertySchemasIndex from '/imports/api/properties/propertySchemasIndex.js';
export default {
- components: {
- ...propertyFormIndex,
- DialogBase,
+ components: {
+ ...propertyFormIndex,
+ DialogBase,
ColorPicker,
- },
- mixins: [schemaFormMixin],
- props: {
- propertyName: String,
- type: String,
- },
+ },
+ mixins: [schemaFormMixin],
+ props: {
+ propertyName: {
+ type: String,
+ default: undefined,
+ },
+ type: {
+ type: String,
+ default: undefined,
+ },
+ },
reactiveProvide: {
name: 'context',
include: ['debounceTime', 'isLibraryForm'],
},
- data(){return {
- model: {
- type: this.type,
- },
- schema: undefined,
- validationContext: undefined,
- debounceTime: 0,
- isLibraryForm: true,
- };},
- watch: {
- type(newType){
- if (!newType) return;
- this.schema = propertySchemasIndex[newType];
- this.validationContext = this.schema.newContext();
- let model = this.schema.clean({});
- model.type = newType;
- this.model = model;
- },
- },
+ data() {
+ return {
+ model: {
+ type: this.type,
+ },
+ schema: undefined,
+ validationContext: undefined,
+ debounceTime: 0,
+ isLibraryForm: true,
+ };
+ },
+ watch: {
+ type(newType) {
+ if (!newType) return;
+ this.schema = propertySchemasIndex[newType];
+ this.validationContext = this.schema.newContext();
+ let model = this.schema.clean({});
+ model.type = newType;
+ this.model = model;
+ },
+ },
}
diff --git a/app/imports/ui/library/MoveLibraryNodeDialog.vue b/app/imports/ui/library/MoveLibraryNodeDialog.vue
index a5824984..ce412813 100644
--- a/app/imports/ui/library/MoveLibraryNodeDialog.vue
+++ b/app/imports/ui/library/MoveLibraryNodeDialog.vue
@@ -23,15 +23,17 @@
diff --git a/app/imports/ui/library/SingleLibraryToolbar.vue b/app/imports/ui/library/SingleLibraryToolbar.vue
index fc953903..c3404d8f 100644
--- a/app/imports/ui/library/SingleLibraryToolbar.vue
+++ b/app/imports/ui/library/SingleLibraryToolbar.vue
@@ -43,24 +43,26 @@ import { assertDocEditPermission } from '/imports/api/sharing/sharingPermissions
import { mapMutations } from 'vuex';
export default {
- data(){ return {
- loading: false,
- }},
+ data() {
+ return {
+ loading: false,
+ }
+ },
meteor: {
- library(){
+ library() {
return Libraries.findOne(this.$route.params.id);
},
- subscribed(){
+ subscribed() {
let libraryId = this.$route.params.id;
let user = Meteor.user();
return user?.subscribedLibraries?.includes(libraryId);
},
- showSubscribeButton(){
+ showSubscribeButton() {
let user = Meteor.user();
let library = this.library;
if (!user || !library) return;
let userId = user._id;
- if (user.subscribedLibraries.includes(library._id)){
+ if (user.subscribedLibraries.includes(library._id)) {
return true
} else if (
library.readers.includes(userId) ||
@@ -72,7 +74,7 @@ export default {
return true;
}
},
- canEdit(){
+ canEdit() {
try {
assertDocEditPermission(this.library, Meteor.userId());
return true
@@ -85,7 +87,7 @@ export default {
...mapMutations([
'toggleDrawer',
]),
- subscribe(value){
+ subscribe(value) {
this.loading = true;
Meteor.users.subscribeToLibrary.call({
libraryId: this.$route.params.id,
@@ -94,16 +96,17 @@ export default {
this.loading = false;
});
},
- editLibrary(){
- this.$store.commit('pushDialogStack', {
- component: 'library-edit-dialog',
- elementId: 'library-edit-button',
- data: {_id: this.$route.params.id},
- });
- },
+ editLibrary() {
+ this.$store.commit('pushDialogStack', {
+ component: 'library-edit-dialog',
+ elementId: 'library-edit-button',
+ data: { _id: this.$route.params.id },
+ });
+ },
},
}
diff --git a/app/imports/ui/markdownCofig.js b/app/imports/ui/markdownCofig.js
index 7fcfeba7..c0ff6a03 100644
--- a/app/imports/ui/markdownCofig.js
+++ b/app/imports/ui/markdownCofig.js
@@ -8,5 +8,5 @@ marked.setOptions({
silent: true,
smartLists: true,
smartypants: true,
- baseUrl: 'https://dicecloud.com',
+ //baseUrl: 'https://dicecloud.com',
});
diff --git a/app/imports/ui/pages/CharacterSheetPage.vue b/app/imports/ui/pages/CharacterSheetPage.vue
index c21908db..a2346e36 100644
--- a/app/imports/ui/pages/CharacterSheetPage.vue
+++ b/app/imports/ui/pages/CharacterSheetPage.vue
@@ -8,8 +8,8 @@
diff --git a/app/imports/ui/pages/Documentation.vue b/app/imports/ui/pages/Documentation.vue
new file mode 100644
index 00000000..c94fe41f
--- /dev/null
+++ b/app/imports/ui/pages/Documentation.vue
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Help document not found for {{ title }}
+
+
+
+
+
+
+
+
+
diff --git a/app/imports/ui/pages/FunctionReference.vue b/app/imports/ui/pages/FunctionReference.vue
new file mode 100644
index 00000000..c03cf804
--- /dev/null
+++ b/app/imports/ui/pages/FunctionReference.vue
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+ Functions
+
+
{{ fn.name }}
+
+ {{ fn.comment }}
+
+
+
+
+ {{ example.input }}
+ |
+
+ mdi-arrow-right
+ |
+
+ {{ example.result }}
+ |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/imports/ui/pages/Home.vue b/app/imports/ui/pages/Home.vue
index 171ade01..72642172 100644
--- a/app/imports/ui/pages/Home.vue
+++ b/app/imports/ui/pages/Home.vue
@@ -132,17 +132,17 @@
diff --git a/app/imports/ui/pages/SignIn.vue b/app/imports/ui/pages/SignIn.vue
index 87f83356..a1a0ba2e 100644
--- a/app/imports/ui/pages/SignIn.vue
+++ b/app/imports/ui/pages/SignIn.vue
@@ -91,53 +91,53 @@
diff --git a/app/imports/ui/pages/SingleLibrary.vue b/app/imports/ui/pages/SingleLibrary.vue
index d564dee1..4faa0452 100644
--- a/app/imports/ui/pages/SingleLibrary.vue
+++ b/app/imports/ui/pages/SingleLibrary.vue
@@ -7,12 +7,29 @@
diff --git a/app/imports/ui/pages/Tabletops.vue b/app/imports/ui/pages/Tabletops.vue
index fca7d1c6..5417feb4 100644
--- a/app/imports/ui/pages/Tabletops.vue
+++ b/app/imports/ui/pages/Tabletops.vue
@@ -37,7 +37,7 @@
import SingleCardLayout from '/imports/ui/layouts/SingleCardLayout.vue'
import Tabletops from '/imports/api/tabletop/Tabletops.js';
import insertTabletop from '/imports/api/tabletop/methods/insertTabletop.js';
-import snackbar from '/imports/ui/components/snackbars/SnackbarQueue.js';
+import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
export default {
components: {
diff --git a/app/imports/ui/properties/components/actions/ActionCard.vue b/app/imports/ui/properties/components/actions/ActionCard.vue
index 50f22c18..040009c9 100644
--- a/app/imports/ui/properties/components/actions/ActionCard.vue
+++ b/app/imports/ui/properties/components/actions/ActionCard.vue
@@ -38,9 +38,7 @@
:disabled="model.insufficientResources || !context.editPermission"
@click.stop="doAction"
>
-
+
-
+
{{ model.name || propertyName }}
@@ -89,16 +85,13 @@
/>
-
+
-
-
+ $emit('sub-click', e)"
/>
@@ -115,9 +108,12 @@ import ItemConsumedView from '/imports/ui/properties/components/actions/ItemCons
import PropertyIcon from '/imports/ui/properties/shared/PropertyIcon.vue';
import RollPopup from '/imports/ui/components/RollPopup.vue';
import MarkdownText from '/imports/ui/components/MarkdownText.vue';
-import {snackbar} from '/imports/ui/components/snackbars/SnackbarQueue.js';
+import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
import CardHighlight from '/imports/ui/components/CardHighlight.vue';
-import CreaturePropertiesTree from '/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue';
+import TreeNodeList from '/imports/ui/components/tree/TreeNodeList.vue';
+import { nodeArrayToTree } from '/imports/api/parenting/nodesToTree.js';
+import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
+import { some } from 'lodash';
export default {
components: {
@@ -127,7 +123,7 @@ export default {
PropertyIcon,
RollPopup,
CardHighlight,
- CreaturePropertiesTree,
+ TreeNodeList,
},
inject: {
context: {
@@ -145,20 +141,22 @@ export default {
required: true,
},
},
- data(){return {
- activated: undefined,
- doActionLoading: false,
- hovering: false,
- }},
+ data() {
+ return {
+ activated: undefined,
+ doActionLoading: false,
+ hovering: false,
+ }
+ },
computed: {
- rollBonus(){
+ rollBonus() {
if (!this.model.attackRoll) return;
return numberToSignedString(this.model.attackRoll.value);
},
- rollBonusTooLong(){
+ rollBonusTooLong() {
return this.rollBonus && this.rollBonus.length > 3;
},
- propertyName(){
+ propertyName() {
return getPropertyName(this.model.type);
},
cardClasses() {
@@ -173,12 +171,41 @@ export default {
actionTypeIcon() {
return `$vuetify.icons.${this.model.actionType}`;
},
- },
+ },
+ meteor: {
+ children() {
+ const indicesOfTerminatingProps = [];
+ const decendants = CreatureProperties.find({
+ 'ancestors.id': this.model._id,
+ 'removed': { $ne: true },
+ }, {
+ sort: {order: 1}
+ }).map(prop => {
+ // Get all the props we don't want to show the decendants of and
+ // where they might appear in the ancestor list
+ if (prop.type === 'buff' || prop.type === 'folder') {
+ indicesOfTerminatingProps.push({
+ id: prop._id,
+ ancestorIndex: prop.ancestors.length,
+ });
+ }
+ return prop;
+ }).filter(prop => {
+ // Filter out folders entirely
+ if (prop.type === 'folder') return false;
+ // Filter out decendants of terminating props
+ return !some(indicesOfTerminatingProps, buffIndex => {
+ return prop.ancestors[buffIndex.ancestorIndex]?.id === buffIndex.id;
+ });
+ });
+ return nodeArrayToTree(decendants);
+ },
+ },
methods: {
- click(e){
- this.$emit('click', e);
- },
- doAction({advantage}){
+ click(e) {
+ this.$emit('click', e);
+ },
+ doAction({ advantage }) {
this.doActionLoading = true;
this.shwing();
doAction.call({
@@ -188,13 +215,13 @@ export default {
}
}, error => {
this.doActionLoading = false;
- if (error){
+ if (error) {
console.error(error);
- snackbar({text: error.reason});
+ snackbar({ text: error.reason });
}
});
},
- shwing(){
+ shwing() {
this.activated = true;
setTimeout(() => {
this.activated = undefined;
@@ -209,9 +236,11 @@ export default {
transition: box-shadow .4s cubic-bezier(0.25, 0.8, 0.25, 1),
transform 0.075s ease;
}
+
.action-card.active {
transform: scale(0.92);
}
+
.action-title {
font-size: 16px;
font-weight: 400;
@@ -222,9 +251,10 @@ export default {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
- transition: .3s cubic-bezier(.25,.8,.5,1);
+ transition: .3s cubic-bezier(.25, .8, .5, 1);
width: 100%;
}
+
.action-sub-title {
color: #9e9e9e;
flex-grow: 0;
@@ -236,15 +266,19 @@ export default {
text-overflow: ellipsis;
width: 100%;
}
+
.action-child {
height: 32px;
}
+
.theme--light.muted-text {
- color: rgba(0,0,0,.3) !important;
+ color: rgba(0, 0, 0, .3) !important;
}
+
.theme--dark.muted-text {
- color: hsla(0,0%,100%,.3) !important;
+ color: hsla(0, 0%, 100%, .3) !important;
}
+
.action-card {
transition: transform 0.15s cubic;
}
@@ -252,12 +286,14 @@ export default {
diff --git a/app/imports/ui/properties/components/attributes/AbilityListTile.vue b/app/imports/ui/properties/components/attributes/AbilityListTile.vue
index c4d748da..46d36bb8 100644
--- a/app/imports/ui/properties/components/attributes/AbilityListTile.vue
+++ b/app/imports/ui/properties/components/attributes/AbilityListTile.vue
@@ -55,7 +55,7 @@
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
import RollPopup from '/imports/ui/components/RollPopup.vue';
import doCheck from '/imports/api/engine/actions/doCheck.js';
-import {snackbar} from '/imports/ui/components/snackbars/SnackbarQueue.js';
+import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
export default {
components: {
@@ -66,23 +66,25 @@ export default {
default: {},
},
},
- props: {
- model: {type: Object, required: true},
- },
- data(){return {
- checkLoading: false,
- }},
- computed: {
- hasClickListener(){
+ props: {
+ model: { type: Object, required: true },
+ },
+ data() {
+ return {
+ checkLoading: false,
+ }
+ },
+ computed: {
+ hasClickListener() {
return this.$listeners && this.$listeners.click
- },
- },
- methods: {
- numberToSignedString,
- click(e){
- this.$emit('click', e);
- },
- check({advantage}){
+ },
+ },
+ methods: {
+ numberToSignedString,
+ click(e) {
+ this.$emit('click', e);
+ },
+ check({ advantage }) {
this.checkLoading = true;
doCheck.call({
propId: this.model._id,
@@ -91,15 +93,15 @@ export default {
},
}, error => {
this.checkLoading = false;
- if (error){
+ if (error) {
console.error(error);
- snackbar({text: error.reason});
+ snackbar({ text: error.reason });
}
});
},
- },
+ },
meteor: {
- swapScoresAndMods(){
+ swapScoresAndMods() {
let user = Meteor.user();
return user &&
user.preferences &&
@@ -110,26 +112,32 @@ export default {
diff --git a/app/imports/ui/properties/components/attributes/AttributeEffect.vue b/app/imports/ui/properties/components/attributes/AttributeEffect.vue
index 687500bc..5725a3ef 100644
--- a/app/imports/ui/properties/components/attributes/AttributeEffect.vue
+++ b/app/imports/ui/properties/components/attributes/AttributeEffect.vue
@@ -27,9 +27,9 @@
{{ displayedText }}
-
+
diff --git a/app/imports/ui/properties/components/attributes/HealthBarCard.vue b/app/imports/ui/properties/components/attributes/HealthBarCard.vue
index f05c7978..c3409ee0 100644
--- a/app/imports/ui/properties/components/attributes/HealthBarCard.vue
+++ b/app/imports/ui/properties/components/attributes/HealthBarCard.vue
@@ -17,17 +17,17 @@
diff --git a/app/imports/ui/properties/components/attributes/HealthBarCardContainer.vue b/app/imports/ui/properties/components/attributes/HealthBarCardContainer.vue
index 9b8440e7..639beee0 100644
--- a/app/imports/ui/properties/components/attributes/HealthBarCardContainer.vue
+++ b/app/imports/ui/properties/components/attributes/HealthBarCardContainer.vue
@@ -12,60 +12,60 @@
diff --git a/app/imports/ui/properties/components/attributes/HitDiceListTile.vue b/app/imports/ui/properties/components/attributes/HitDiceListTile.vue
index e26f1abd..7cfff667 100644
--- a/app/imports/ui/properties/components/attributes/HitDiceListTile.vue
+++ b/app/imports/ui/properties/components/attributes/HitDiceListTile.vue
@@ -31,9 +31,7 @@
-
+
{{ model.value }}
@@ -63,60 +61,71 @@ export default {
inject: {
context: { default: {} }
},
- props: {
+ props: {
model: {
type: Object,
required: true,
}
- },
- data(){ return{
- hover: false,
- }},
+ },
+ data() {
+ return {
+ hover: false,
+ }
+ },
computed: {
- signedConMod(){
+ signedConMod() {
return numberToSignedString(this.model.constitutionMod);
},
},
- methods: {
- click(e){
- this.$emit('click', e);
- },
- increment(value){
- this.$emit('change', {type: 'increment', value})
- },
- },
+ methods: {
+ click(e) {
+ this.$emit('click', e);
+ },
+ increment(value) {
+ this.$emit('change', { type: 'increment', value })
+ },
+ },
};
diff --git a/app/imports/ui/properties/components/attributes/ResourceCard.vue b/app/imports/ui/properties/components/attributes/ResourceCard.vue
index 44390756..c5759892 100644
--- a/app/imports/ui/properties/components/attributes/ResourceCard.vue
+++ b/app/imports/ui/properties/components/attributes/ResourceCard.vue
@@ -22,9 +22,7 @@
mdi-chevron-down
-
+
{{ model.value }}
@@ -53,55 +51,64 @@
diff --git a/app/imports/ui/properties/components/attributes/SpellSlotListTile.vue b/app/imports/ui/properties/components/attributes/SpellSlotListTile.vue
index 02afc030..584fc765 100644
--- a/app/imports/ui/properties/components/attributes/SpellSlotListTile.vue
+++ b/app/imports/ui/properties/components/attributes/SpellSlotListTile.vue
@@ -7,9 +7,7 @@
v-on="hasClickListener ? {click} : {}"
>
-
+
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
export default {
- props: {
- model: {
+ props: {
+ model: {
type: Object,
required: true,
},
dark: Boolean,
hideCastButton: Boolean,
disabled: Boolean,
- },
- computed: {
- hasClickListener(){
+ },
+ computed: {
+ hasClickListener() {
return this.$listeners && !!this.$listeners.click;
},
- },
- methods: {
- signed: numberToSignedString,
- click(e){
- this.$emit('click', e);
- },
- },
+ },
+ methods: {
+ signed: numberToSignedString,
+ click(e) {
+ this.$emit('click', e);
+ },
+ },
};
diff --git a/app/imports/ui/properties/components/features/FeatureCard.vue b/app/imports/ui/properties/components/features/FeatureCard.vue
index 0f706b3e..860e11de 100644
--- a/app/imports/ui/properties/components/features/FeatureCard.vue
+++ b/app/imports/ui/properties/components/features/FeatureCard.vue
@@ -10,7 +10,7 @@
-
+
diff --git a/app/imports/ui/properties/components/inventory/ItemList.vue b/app/imports/ui/properties/components/inventory/ItemList.vue
index 6696ee12..28a07995 100644
--- a/app/imports/ui/properties/components/inventory/ItemList.vue
+++ b/app/imports/ui/properties/components/inventory/ItemList.vue
@@ -52,40 +52,42 @@ export default {
preparingSpells: Boolean,
equipment: Boolean,
},
- data(){ return {
- dataItems: [],
- }},
+ data() {
+ return {
+ dataItems: [],
+ }
+ },
computed: {
- levels(){
+ levels() {
let levels = new Set();
this.items.forEach(item => levels.add(item.level));
return levels;
},
},
watch: {
- items(value){
+ items(value) {
this.dataItems = value;
}
},
- mounted(){
+ mounted() {
this.dataItems = this.items;
},
methods: {
- clickProperty(_id){
- this.$store.commit('pushDialogStack', {
- component: 'creature-property-dialog',
- elementId: _id,
- data: {_id},
- });
- },
- change({added, moved}){
+ clickProperty(_id) {
+ this.$store.commit('pushDialogStack', {
+ component: 'creature-property-dialog',
+ elementId: _id,
+ data: { _id },
+ });
+ },
+ change({ added, moved }) {
let event = added || moved;
- if (event){
+ if (event) {
// If this item is now adjacent to another, set the order accordingly
let order;
let before = this.dataItems[event.newIndex - 1];
let after = this.dataItems[event.newIndex + 1];
- if (before && before._id){
+ if (before && before._id) {
order = before.order + 0.5;
} else if (after && after._id) {
order = after.order - 0.5;
@@ -101,7 +103,7 @@ export default {
parentRef: this.parentRef,
order,
});
- if (doc.type === 'item' && doc.equipped != this.equipment){
+ if (doc.type === 'item' && doc.equipped != this.equipment) {
updateCreatureProperty.call({
_id: doc._id,
path: ['equipped'],
@@ -111,6 +113,6 @@ export default {
}
setTimeout(() => this.dataItems = this.items, 0);
},
- }
+ }
}
diff --git a/app/imports/ui/properties/components/inventory/ItemListTile.vue b/app/imports/ui/properties/components/inventory/ItemListTile.vue
index d6e64249..5dfa1b8e 100644
--- a/app/imports/ui/properties/components/inventory/ItemListTile.vue
+++ b/app/imports/ui/properties/components/inventory/ItemListTile.vue
@@ -49,10 +49,10 @@ import treeNodeViewMixin from '/imports/ui/properties/treeNodeViews/treeNodeView
import PROPERTIES from '/imports/constants/PROPERTIES.js';
import adjustQuantity from '/imports/api/creature/creatureProperties/methods/adjustQuantity.js';
import IncrementButton from '/imports/ui/components/IncrementButton.vue';
-import {snackbar} from '/imports/ui/components/snackbars/SnackbarQueue.js';
+import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
export default {
- components:{
+ components: {
IncrementButton,
},
mixins: [treeNodeViewMixin],
@@ -62,20 +62,22 @@ export default {
props: {
preparingSpells: Boolean,
},
- data(){return {
- incrementLoading: false,
- }},
+ data() {
+ return {
+ incrementLoading: false,
+ }
+ },
computed: {
- hasClickListener(){
+ hasClickListener() {
return this.$listeners && !!this.$listeners.click;
},
- title(){
+ title() {
let model = this.model;
if (!model) return;
- if (model.quantity !== 1){
- if (model.plural){
+ if (model.quantity !== 1) {
+ if (model.plural) {
return `${model.quantity} ${model.plural}`;
- } else if (model.name){
+ } else if (model.name) {
return `${model.quantity} ${model.name}`;
}
} else if (model.name) {
@@ -86,10 +88,10 @@ export default {
}
},
methods: {
- click(e){
- this.$emit('click', e);
- },
- changeQuantity({type, value}) {
+ click(e) {
+ this.$emit('click', e);
+ },
+ changeQuantity({ type, value }) {
this.incrementLoading = true;
adjustQuantity.call({
_id: this.model._id,
@@ -97,8 +99,8 @@ export default {
value: value
}, error => {
this.incrementLoading = false;
- if (error){
- snackbar({text: error.reason});
+ if (error) {
+ snackbar({ text: error.reason });
console.error(error);
}
});
@@ -111,6 +113,7 @@ export default {
.item-avatar {
min-width: 32px;
}
+
.item {
background-color: inherit;
}
diff --git a/app/imports/ui/properties/components/persona/NoteCard.vue b/app/imports/ui/properties/components/persona/NoteCard.vue
index f3be2a0e..d07afa1e 100644
--- a/app/imports/ui/properties/components/persona/NoteCard.vue
+++ b/app/imports/ui/properties/components/persona/NoteCard.vue
@@ -31,10 +31,10 @@ import isDarkColor from '/imports/ui/utility/isDarkColor.js';
import CardHighlight from '/imports/ui/components/CardHighlight.vue';
export default {
- components: {
- PropertyDescription,
+ components: {
+ PropertyDescription,
CardHighlight,
- },
+ },
inject: {
theme: {
default: {
@@ -42,31 +42,34 @@ export default {
},
},
},
- props: {
- model: {
+ props: {
+ model: {
type: Object,
required: true,
},
- },
- data(){ return{
- hover: false,
- }},
+ },
+ data() {
+ return {
+ hover: false,
+ }
+ },
computed: {
- isDark(){
+ isDark() {
return isDarkColor(this.model.color);
},
},
- methods: {
- clickProperty(_id){
- this.$store.commit('pushDialogStack', {
- component: 'creature-property-dialog',
- elementId: `${_id}`,
- data: {_id},
- });
- },
- },
+ methods: {
+ clickProperty(_id) {
+ this.$store.commit('pushDialogStack', {
+ component: 'creature-property-dialog',
+ elementId: `${_id}`,
+ data: { _id },
+ });
+ },
+ },
};
diff --git a/app/imports/ui/properties/components/pointBuy/PointBuyCard.vue b/app/imports/ui/properties/components/pointBuy/PointBuyCard.vue
new file mode 100644
index 00000000..cbd3f339
--- /dev/null
+++ b/app/imports/ui/properties/components/pointBuy/PointBuyCard.vue
@@ -0,0 +1,72 @@
+
+
+
+
+ {{ model.name || 'Point Buy' }}
+
+
+ {{ model.spent }}
+
+ / {{ model.total && model.total.value }}
+
+
+
+
+
+
+ mdi-close
+
+
+
+
+
+
diff --git a/app/imports/ui/properties/components/skills/SkillListTile.vue b/app/imports/ui/properties/components/skills/SkillListTile.vue
index 45f8b138..bbcb773e 100644
--- a/app/imports/ui/properties/components/skills/SkillListTile.vue
+++ b/app/imports/ui/properties/components/skills/SkillListTile.vue
@@ -8,7 +8,7 @@
-
+
{{ model.name }}
*
@@ -62,7 +62,7 @@ import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
import ProficiencyIcon from '/imports/ui/properties/shared/ProficiencyIcon.vue';
import RollPopup from '/imports/ui/components/RollPopup.vue';
import doCheck from '/imports/api/engine/actions/doCheck.js';
-import {snackbar} from '/imports/ui/components/snackbars/SnackbarQueue.js';
+import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
export default {
components: {
@@ -74,37 +74,39 @@ export default {
default: {},
},
},
- props: {
+ props: {
model: {
type: Object,
required: true,
},
hideModifier: Boolean,
- },
- data(){return {
- checkLoading: false,
- }},
- computed: {
- displayedModifier(){
- let mod = this.model.value;
- if (this.model.fail){
- return 'fail';
- } else {
- return numberToSignedString(mod);
- }
- },
- hasClickListener(){
+ },
+ data() {
+ return {
+ checkLoading: false,
+ }
+ },
+ computed: {
+ displayedModifier() {
+ let mod = this.model.value;
+ if (this.model.fail) {
+ return 'fail';
+ } else {
+ return numberToSignedString(mod);
+ }
+ },
+ hasClickListener() {
return this.$listeners && this.$listeners.click
- },
- passiveScore(){
+ },
+ passiveScore() {
return 10 + this.model.value + this.model.passiveBonus;
}
- },
- methods: {
- click(e){
- this.$emit('click', e);
- },
- check({advantage}){
+ },
+ methods: {
+ click(e) {
+ this.$emit('click', e);
+ },
+ check({ advantage }) {
this.checkLoading = true;
doCheck.call({
propId: this.model._id,
@@ -113,24 +115,26 @@ export default {
},
}, error => {
this.checkLoading = false;
- if (error){
+ if (error) {
console.error(error);
- snackbar({text: error.reason});
+ snackbar({ text: error.reason });
}
});
},
- }
+ }
}
diff --git a/app/imports/ui/properties/components/spells/CastSpellWithSlotDialog.vue b/app/imports/ui/properties/components/spells/CastSpellWithSlotDialog.vue
index 04db8066..dfdc0160 100644
--- a/app/imports/ui/properties/components/spells/CastSpellWithSlotDialog.vue
+++ b/app/imports/ui/properties/components/spells/CastSpellWithSlotDialog.vue
@@ -91,6 +91,20 @@
+
+
+
+ Cast as ritual
+
+
+
Spell
@@ -145,10 +159,24 @@
>
Cancel
+
+ Cast
+
Cast
@@ -164,20 +192,22 @@ import CreatureProperties from '/imports/api/creature/creatureProperties/Creatur
import spellsWithSubheaders from '/imports/ui/properties/components/spells/spellsWithSubheaders.js';
import SpellSlotListTile from '/imports/ui/properties/components/attributes/SpellSlotListTile.vue';
import SpellListTile from '/imports/ui/properties/components/spells/SpellListTile.vue';
+import RollPopup from '/imports/ui/components/RollPopup.vue';
import { find } from 'lodash';
const slotFilter = {
type: 'attribute',
attributeType: 'spellSlot',
- removed: {$ne: true},
- inactive: {$ne: true},
- overridden: {$ne: true},
- 'spellSlotLevel.value': {$gte: 1},
+ removed: { $ne: true },
+ inactive: { $ne: true },
+ overridden: { $ne: true },
+ 'spellSlotLevel.value': { $gte: 1 },
};
export default {
components: {
DialogBase,
+ RollPopup,
SplitListLayout,
SpellSlotListTile,
SpellListTile,
@@ -196,36 +226,38 @@ export default {
default: undefined,
},
},
- data(){ return {
- searchString: undefined,
- selectedSlotId: this.slotId,
- selectedSpellId: this.spellId,
- selectedSlot: undefined,
- selectedSpell: undefined,
- searchValue: undefined,
- searchError: undefined,
- filterMenuOpen: false,
- booleanFilters: {
- verbal: {name: 'Verbal', enabled: false, value: false},
- somatic: {name: 'Somatic', enabled: false, value: false},
- material: {name: 'Material', enabled: false, value: false},
- concentration: {name: 'Concentration', enabled: false, value: false},
- ritual: {name: 'Ritual', enabled: false, value: false},
- },
- }},
+ data() {
+ return {
+ searchString: undefined,
+ selectedSlotId: this.slotId,
+ selectedSpellId: this.spellId,
+ selectedSlot: undefined,
+ selectedSpell: undefined,
+ searchValue: undefined,
+ searchError: undefined,
+ filterMenuOpen: false,
+ booleanFilters: {
+ verbal: { name: 'Verbal', enabled: false, value: true },
+ somatic: { name: 'Somatic', enabled: false, value: true },
+ material: { name: 'Material', enabled: false, value: true },
+ concentration: { name: 'Concentration', enabled: false, value: true },
+ ritual: { name: 'Ritual', enabled: false, value: true },
+ },
+ }
+ },
computed: {
- computedSpells(){
+ computedSpells() {
return spellsWithSubheaders(this.spells);
},
- canCast(){
+ canCast() {
if (!this.selectedSpell || !this.selectedSlotId) return false;
return this.canCastSpellWithSlot(
this.selectedSpell, this.selectedSlotId, this.selectedSlot
);
},
- filtersApplied(){
- for (let key in this.booleanFilters){
- if (this.booleanFilters[key].enabled){
+ filtersApplied() {
+ for (let key in this.booleanFilters) {
+ if (this.booleanFilters[key].enabled) {
return true;
}
}
@@ -234,79 +266,82 @@ export default {
},
watch: {
selectedSpellId: {
- handler(spellId){
+ handler(spellId) {
this.selectedSpell = CreatureProperties.findOne(spellId)
},
immediate: true
},
selectedSpell: {
- handler(spell){
+ handler(spell) {
if (!spell) return;
- if(spell.level === 0 || spell.castWithoutSpellSlots){
- this.selectedSlotId = 'no-slot';
- } else if (
- !this.selectedSlotId ||
- this.selectedSlotId == 'no-slot' ||
- this.selectedSlot.spellSlotLevel.value < spell.level
+ if (this.selectedSlotId && this.canCastSpellWithSlot(
+ spell, this.selectedSlotId, this.selectedSlot
+ )) return;
+ if (
+ (spell.level === 0 || spell.castWithoutSpellSlots)
) {
+ this.selectedSlotId = 'no-slot';
+ } else {
const newSlot = find(
CreatureProperties.find({
'ancestors.id': this.creatureId,
...slotFilter
}, {
- sort: {'spellSlotLevel.value': 1, order: 1},
+ sort: { 'spellSlotLevel.value': 1, order: 1 },
}).fetch(),
slot => {
return this.canCastSpellWithSlot(spell, slot._id, slot)
}
);
- if (newSlot){
+ if (newSlot) {
this.selectedSlotId = newSlot._id;
+ } else if (spell.ritual) {
+ this.selectedSlotId = 'ritual';
}
}
},
immediate: true,
},
selectedSlotId: {
- handler(slotId){
+ handler(slotId) {
this.selectedSlot = CreatureProperties.findOne(slotId);
},
immediate: true
},
- selectedSlot:{
- handler(slot){
+ selectedSlot: {
+ handler(slot) {
if (!slot) return;
if (!this.selectedSpell) return;
- if(this.selectedSpell.level > slot.spellSlotLevel.value){
+ if (this.selectedSpell.level > slot.spellSlotLevel.value) {
this.selectedSpellId = undefined;
}
},
immediate: true,
},
},
- mounted(){
- if (this.selectedSpellId){
- this.$vuetify.goTo('.spell.v-list-item--active', {container: '.right'});
+ mounted() {
+ if (this.selectedSpellId) {
+ this.$vuetify.goTo('.spell.v-list-item--active', { container: '.right' });
}
},
methods: {
- clearBooleanFilters(){
- for (let key in this.booleanFilters){
+ clearBooleanFilters() {
+ for (let key in this.booleanFilters) {
this.booleanFilters[key].enabled = false;
}
},
- spellDialog(_id){
+ spellDialog(_id) {
this.$store.commit('pushDialogStack', {
- component: 'creature-property-dialog',
- elementId: `spell-info-btn-${_id}`,
- data: {_id},
- });
+ component: 'creature-property-dialog',
+ elementId: `spell-info-btn-${_id}`,
+ data: { _id },
+ });
},
- searchChanged(val, ack){
+ searchChanged(val, ack) {
this.searchValue = val;
setTimeout(ack, 200);
},
- canCastSpellWithSlot(spell, slotId, slot){
+ canCastSpellWithSlot(spell, slotId, slot) {
if (slot && !slot.value) return false;
if (!spell) return true;
if (!slotId) return true;
@@ -314,66 +349,69 @@ export default {
spell.castWithoutSpellSlots &&
spell.insufficientResources
) return false;
- return (!spell.level || spell.castWithoutSpellSlots) ? (
+ if (spell.ritual && slotId === 'ritual') return true;
+ if (!spell.level || spell.castWithoutSpellSlots) {
// Cantrips and no-slot spells
- slotId && slotId === 'no-slot'
- ) : (
+ return slotId && slotId === 'no-slot'
+ } else {
// Leveled spells
- slotId !== 'no-slot' &&
- slot && spell && (
- spell.level <= slot.spellSlotLevel.value
- )
- )
+ return slotId !== 'no-slot' && slot && spell && (
+ spell.level <= slot.spellSlotLevel.value
+ );
+ }
},
- cast(){
+ cast({ advantage }) {
let selectedSlotId = this.selectedSlotId;
- if (selectedSlotId === 'no-slot') selectedSlotId = undefined;
+ const ritual = selectedSlotId === 'ritual';
+ if (selectedSlotId === 'no-slot' || selectedSlotId === 'ritual') selectedSlotId = undefined;
this.$store.dispatch('popDialogStack', {
spellId: this.selectedSpellId,
slotId: selectedSlotId,
- })
+ advantage,
+ ritual,
+ });
}
},
meteor: {
- spells(){
+ spells() {
let filter = {
'ancestors.id': this.creatureId,
- removed: {$ne: true},
- inactive: {$ne: true},
+ removed: { $ne: true },
+ inactive: { $ne: true },
$or: [
- {prepared: true},
- {alwaysPrepared: true},
+ { prepared: true },
+ { alwaysPrepared: true },
],
};
// Apply the filters from the filter menu
- for (let key in this.booleanFilters){
- if (this.booleanFilters[key].enabled){
+ for (let key in this.booleanFilters) {
+ if (this.booleanFilters[key].enabled) {
let value = this.booleanFilters[key].value;
- if (key === 'material'){
- filter[key] = {$exists: this.booleanFilters[key].value};
+ if (key === 'material') {
+ filter[key] = { $exists: this.booleanFilters[key].value };
} else {
- filter[key] = value ? true: {$ne: true};
+ filter[key] = value ? true : { $ne: true };
}
}
}
// Apply the search string to the name field
- if (this.searchValue){
+ if (this.searchValue) {
filter.name = {
$regex: this.searchValue.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'),
$options: 'i'
};
}
return CreatureProperties.find(filter, {
- sort: {order: 1}
+ sort: { order: 1 }
});
},
- spellSlots(){
+ spellSlots() {
return CreatureProperties.find({
'ancestors.id': this.creatureId,
...slotFilter
}, {
- sort: {'spellSlotLevel.value': 1, order: 1},
+ sort: { 'spellSlotLevel.value': 1, order: 1 },
});
},
},
@@ -381,10 +419,11 @@ export default {
diff --git a/app/imports/ui/properties/components/spells/SpellList.vue b/app/imports/ui/properties/components/spells/SpellList.vue
index 3d1d6333..50f70bfc 100644
--- a/app/imports/ui/properties/components/spells/SpellList.vue
+++ b/app/imports/ui/properties/components/spells/SpellList.vue
@@ -62,48 +62,50 @@ export default {
},
preparingSpells: Boolean,
},
- data(){ return {
- dataSpells: [],
- }},
+ data() {
+ return {
+ dataSpells: [],
+ }
+ },
computed: {
- levels(){
+ levels() {
let levels = new Set();
this.spells.forEach(spell => levels.add(spell.level));
return levels;
},
computedSpells: {
- get(){
+ get() {
return spellsWithSubheaders(this.dataSpells);
},
- set(value){
+ set(value) {
this.dataSpells = value;
},
}
},
watch: {
- spells(value){
+ spells(value) {
this.dataSpells = spellsWithSubheaders(value);
}
},
- mounted(){
+ mounted() {
this.dataSpells = spellsWithSubheaders(this.spells);
},
methods: {
- clickProperty(_id){
- this.$store.commit('pushDialogStack', {
- component: 'creature-property-dialog',
- elementId: `spell-list-tile-${_id}`,
- data: {_id},
- });
- },
- change({added, moved}){
+ clickProperty(_id) {
+ this.$store.commit('pushDialogStack', {
+ component: 'creature-property-dialog',
+ elementId: `spell-list-tile-${_id}`,
+ data: { _id },
+ });
+ },
+ change({ added, moved }) {
let event = added || moved;
- if (event){
+ if (event) {
// If this spell is now adjacent to another, set the order accordingly
let order;
let before = this.dataSpells[event.newIndex - 1];
let after = this.dataSpells[event.newIndex + 1];
- if (before && before._id){
+ if (before && before._id) {
order = before.order + 0.5;
} else if (after && after._id) {
order = after.order - 0.5;
@@ -121,9 +123,10 @@ export default {
});
}
},
- }
+ }
}
diff --git a/app/imports/ui/properties/components/spells/SpellListCard.vue b/app/imports/ui/properties/components/spells/SpellListCard.vue
index c45c7cc3..4dd5edc4 100644
--- a/app/imports/ui/properties/components/spells/SpellListCard.vue
+++ b/app/imports/ui/properties/components/spells/SpellListCard.vue
@@ -63,32 +63,34 @@ import SpellList from '/imports/ui/properties/components/spells/SpellList.vue';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
export default {
- components: {
- ToolbarCard,
+ components: {
+ ToolbarCard,
SpellList,
- },
- props: {
- model: {
+ },
+ props: {
+ model: {
type: Object,
required: true,
},
- organize: Boolean,
- },
- data(){ return {
- preparingSpells: false,
- }},
+ organize: Boolean,
+ },
+ data() {
+ return {
+ preparingSpells: false,
+ }
+ },
meteor: {
- spells(){
+ spells() {
let filter = {
'ancestors.id': this.model._id,
type: 'spell',
- removed: {$ne: true},
+ removed: { $ne: true },
};
- if (this.preparingSpells){
- filter.deactivatedByAncestor = {$ne: true};
- filter.deactivatedByToggle = {$ne: true};
+ if (this.preparingSpells) {
+ filter.deactivatedByAncestor = { $ne: true };
+ filter.deactivatedByToggle = { $ne: true };
} else {
- filter.inactive = {$ne: true};
+ filter.inactive = { $ne: true };
}
return CreatureProperties.find(filter, {
sort: {
@@ -97,35 +99,36 @@ export default {
}
});
},
- numPrepared(){
+ numPrepared() {
return CreatureProperties.find({
'ancestors.id': this.model._id,
type: 'spell',
- removed: {$ne: true},
+ removed: { $ne: true },
prepared: true,
- alwaysPrepared: {$ne: true},
- deactivatedByAncestor: {$ne: true},
- deactivatedByToggle: {$ne: true},
+ alwaysPrepared: { $ne: true },
+ deactivatedByAncestor: { $ne: true },
+ deactivatedByToggle: { $ne: true },
}).count();
},
- preparedError(){
+ preparedError() {
if (!this.model.maxPrepared) return;
let numPrepared = this.numPrepared;
let maxPrepared = this.model.maxPrepared.value || 0;
return numPrepared !== maxPrepared
},
},
- methods: {
- clickSpellList(_id){
- this.$store.commit('pushDialogStack', {
- component: 'creature-property-dialog',
- elementId: `${_id}`,
- data: {_id},
- });
- },
- }
+ methods: {
+ clickSpellList(_id) {
+ this.$store.commit('pushDialogStack', {
+ component: 'creature-property-dialog',
+ elementId: `${_id}`,
+ data: { _id },
+ });
+ },
+ }
};
diff --git a/app/imports/ui/properties/components/spells/SpellListTile.vue b/app/imports/ui/properties/components/spells/SpellListTile.vue
index 1e6af252..20122630 100644
--- a/app/imports/ui/properties/components/spells/SpellListTile.vue
+++ b/app/imports/ui/properties/components/spells/SpellListTile.vue
@@ -67,10 +67,10 @@ export default {
disabled: Boolean,
},
computed: {
- hasClickListener(){
+ hasClickListener() {
return this.$listeners && !!this.$listeners.click;
},
- spellComponents(){
+ spellComponents() {
let components = [];
if (this.model.ritual) components.push('R');
if (this.model.concentration) components.push('C');
@@ -81,10 +81,10 @@ export default {
},
},
methods: {
- click(e){
- this.$emit('click', e);
- },
- setPrepared(val, ack){
+ click(e) {
+ this.$emit('click', e);
+ },
+ setPrepared(val, ack) {
updateCreatureProperty.call({
_id: this.model._id,
path: ['prepared'],
@@ -99,13 +99,17 @@ export default {
.spell-avatar {
min-width: 32px;
}
+
.spell {
background-color: inherit;
}
-.primary--text .v-icon, .primary--text .v-list__tile__sub-title {
+
+.primary--text .v-icon,
+.primary--text .v-list__tile__sub-title {
color: #b71c1c
}
-.theme--light.info-icon{
- color: rgba(0,0,0,.54) !important;
+
+.theme--light.info-icon {
+ color: rgba(0, 0, 0, .54) !important;
}
diff --git a/app/imports/ui/properties/forms/ActionForm.vue b/app/imports/ui/properties/forms/ActionForm.vue
index c550d75a..91bebdd2 100644
--- a/app/imports/ui/properties/forms/ActionForm.vue
+++ b/app/imports/ui/properties/forms/ActionForm.vue
@@ -141,6 +141,18 @@
@change="change('usesUsed', ...arguments)"
/>
+
+
+
+
diff --git a/app/imports/ui/properties/forms/AttributeForm.vue b/app/imports/ui/properties/forms/AttributeForm.vue
index 0b23d1df..42814d86 100644
--- a/app/imports/ui/properties/forms/AttributeForm.vue
+++ b/app/imports/ui/properties/forms/AttributeForm.vue
@@ -140,9 +140,7 @@
-
+
diff --git a/app/imports/ui/properties/forms/AttributesConsumedListForm.vue b/app/imports/ui/properties/forms/AttributesConsumedListForm.vue
index b0a847de..97ff2d81 100644
--- a/app/imports/ui/properties/forms/AttributesConsumedListForm.vue
+++ b/app/imports/ui/properties/forms/AttributesConsumedListForm.vue
@@ -29,13 +29,13 @@
diff --git a/app/imports/ui/properties/forms/BranchForm.vue b/app/imports/ui/properties/forms/BranchForm.vue
index 1d6fe81c..1ad49fb4 100644
--- a/app/imports/ui/properties/forms/BranchForm.vue
+++ b/app/imports/ui/properties/forms/BranchForm.vue
@@ -38,6 +38,12 @@
:value="model.tags"
@change="change('tags', ...arguments)"
/>
+
diff --git a/app/imports/ui/properties/forms/BuffForm.vue b/app/imports/ui/properties/forms/BuffForm.vue
index ff395f4f..ade759e4 100644
--- a/app/imports/ui/properties/forms/BuffForm.vue
+++ b/app/imports/ui/properties/forms/BuffForm.vue
@@ -44,15 +44,45 @@
>
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/imports/ui/properties/forms/BuffRemoverForm.vue b/app/imports/ui/properties/forms/BuffRemoverForm.vue
index f98d7adc..ed5845af 100644
--- a/app/imports/ui/properties/forms/BuffRemoverForm.vue
+++ b/app/imports/ui/properties/forms/BuffRemoverForm.vue
@@ -115,6 +115,20 @@
:value="model.tags"
@change="change('tags', ...arguments)"
/>
+
+
+
+
+
diff --git a/app/imports/ui/properties/forms/ClassForm.vue b/app/imports/ui/properties/forms/ClassForm.vue
index d301b750..f4bd101e 100644
--- a/app/imports/ui/properties/forms/ClassForm.vue
+++ b/app/imports/ui/properties/forms/ClassForm.vue
@@ -1,8 +1,6 @@