All properties added to the sheet now use the type/library/create UX
This commit is contained in:
@@ -47,7 +47,7 @@ const PROPERTIES = Object.freeze({
|
||||
name: 'Container',
|
||||
helpText: 'A container holds items in the inventory',
|
||||
examples: 'Coin pouch, backpack',
|
||||
suggestedParents: [],
|
||||
suggestedParents: ['folder'],
|
||||
},
|
||||
damage: {
|
||||
icon: '$vuetify.icons.damage',
|
||||
|
||||
@@ -31,10 +31,10 @@
|
||||
:key="type"
|
||||
color="primary"
|
||||
:data-id="`insert-creature-property-type-${type}`"
|
||||
:label="'New ' + properties[type].name"
|
||||
:icon="properties[type].icon"
|
||||
:label="type ? 'New ' + properties[type].name : 'New Property'"
|
||||
:icon="type ? properties[type].icon : 'mdi-plus'"
|
||||
:disabled="!editPermission"
|
||||
@click="insertPropertyOfType(type)"
|
||||
@click="addProperty(type)"
|
||||
/>
|
||||
<template v-if="tabNumber === 5">
|
||||
<labeled-fab
|
||||
@@ -42,7 +42,7 @@
|
||||
color="primary"
|
||||
data-id="add-creature-property-btn"
|
||||
label="Add Property"
|
||||
icon="mdi-pencil"
|
||||
icon="mdi-plus"
|
||||
:disabled="!editPermission"
|
||||
@click="addProperty"
|
||||
/>
|
||||
@@ -53,10 +53,11 @@
|
||||
<script lang="js">
|
||||
import LabeledFab from '/imports/ui/components/LabeledFab.vue';
|
||||
import { getHighestOrder } from '/imports/api/parenting/order.js';
|
||||
import insertProperty, { insertPropertyAsChildOfTag } from '/imports/api/creature/creatureProperties/methods/insertProperty.js';
|
||||
import insertProperty from '/imports/api/creature/creatureProperties/methods/insertProperty.js';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import PROPERTIES from '/imports/constants/PROPERTIES.js';
|
||||
import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js';
|
||||
import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js';
|
||||
|
||||
function getParentAndOrderFromSelectedTreeNode(creatureId){
|
||||
// find the parent based on the currently selected property
|
||||
@@ -140,120 +141,49 @@
|
||||
'inventory': ['item', 'container'],
|
||||
'spells': ['spellList', 'spell'],
|
||||
'character': ['note'],
|
||||
'tree': [],
|
||||
'tree': [null],
|
||||
};},
|
||||
properties(){
|
||||
return PROPERTIES;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
insertPropertyOfType(type){
|
||||
addProperty(forcedType){
|
||||
let creatureId = this.creatureId;
|
||||
let fab = hideFab();
|
||||
|
||||
// Open the dialog to insert the property
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-creation-dialog',
|
||||
elementId: 'insert-creature-property-type-' + type,
|
||||
data: {
|
||||
forcedType: type,
|
||||
},
|
||||
callback(creatureProperty){
|
||||
if (!creatureProperty) return 'insert-creature-property-fab';
|
||||
revealFab(fab);
|
||||
|
||||
// Insert the property
|
||||
creatureProperty.order = getHighestOrder({
|
||||
collection: CreatureProperties,
|
||||
ancestorId: creatureId
|
||||
}) + 1;
|
||||
|
||||
let tagDetails;
|
||||
switch (type){
|
||||
case 'item':
|
||||
tagDetails = {tag: 'carried', name: 'Carried'};
|
||||
break;
|
||||
case 'container':
|
||||
tagDetails = {tag: 'inventory', name: 'Inventory'};
|
||||
break;
|
||||
default:
|
||||
tagDetails = {tag: `${type}s`};
|
||||
break;
|
||||
}
|
||||
let id = insertPropertyAsChildOfTag.call({
|
||||
creatureProperty,
|
||||
creatureId,
|
||||
tag: tagDetails.tag,
|
||||
tagDefaultName: tagDetails.name,
|
||||
});
|
||||
return id;
|
||||
}
|
||||
});
|
||||
},
|
||||
insertTreeProperty(){
|
||||
let creatureId = this.creatureId;
|
||||
let fab = hideFab();
|
||||
// Open the dialog to insert the property
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-creation-dialog',
|
||||
elementId: 'insert-creature-property-btn',
|
||||
callback(creatureProperty){
|
||||
if (!creatureProperty) return 'insert-creature-property-fab';
|
||||
revealFab(fab);
|
||||
|
||||
// Get order and parent
|
||||
let {parentRef, order } = getParentAndOrderFromSelectedTreeNode(creatureId);
|
||||
creatureProperty.order = order;
|
||||
|
||||
// Insert the property
|
||||
let id = insertProperty.call({creatureProperty, parentRef});
|
||||
return `tree-node-${id}`;
|
||||
}
|
||||
});
|
||||
},
|
||||
propertyFromLibrary(){
|
||||
let creatureId = this.creatureId;
|
||||
let fab = hideFab();
|
||||
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-from-library-dialog',
|
||||
elementId: 'insert-creature-property-from-library-btn',
|
||||
callback(libraryNode){
|
||||
if (!libraryNode) return 'insert-creature-property-fab';
|
||||
revealFab(fab);
|
||||
|
||||
let nodeId = libraryNode._id;
|
||||
let {parentRef, order } = getParentAndOrderFromSelectedTreeNode(creatureId);
|
||||
|
||||
let id = insertPropertyFromLibraryNode.call({nodeIds: [nodeId], parentRef, order});
|
||||
return `tree-node-${id}`;
|
||||
}
|
||||
});
|
||||
},
|
||||
addProperty(){
|
||||
let creatureId = this.creatureId;
|
||||
let fab = hideFab();
|
||||
let {parentRef, order } = getParentAndOrderFromSelectedTreeNode(creatureId);
|
||||
let parent;
|
||||
try {
|
||||
parent = fetchDocByRef(parentRef);
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'add-creature-property-dialog',
|
||||
elementId: 'add-creature-property-btn',
|
||||
elementId: 'insert-creature-property-type-' + forcedType,
|
||||
data: {
|
||||
parentDoc: forcedType ? undefined : parent,
|
||||
forcedType,
|
||||
},
|
||||
callback(result){
|
||||
revealFab(fab);
|
||||
if (!result){
|
||||
return 'insert-creature-property-fab';
|
||||
}
|
||||
let {parentRef, order } = getParentAndOrderFromSelectedTreeNode(creatureId);
|
||||
if (Array.isArray(result)){
|
||||
revealFab(fab);
|
||||
let nodeIds = result;
|
||||
let id = insertPropertyFromLibraryNode.call({nodeIds, parentRef, order});
|
||||
return `tree-node-${id}`;
|
||||
return forcedType ? id : `tree-node-${id}`;
|
||||
} else {
|
||||
revealFab(fab);
|
||||
let creatureProperty = result;
|
||||
// Get order and parent
|
||||
creatureProperty.order = order;
|
||||
// Insert the property
|
||||
let id = insertProperty.call({creatureProperty, parentRef});
|
||||
return `tree-node-${id}`;
|
||||
return forcedType ? id : `tree-node-${id}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,50 +1,127 @@
|
||||
<template lang="html">
|
||||
<selectable-property-dialog
|
||||
:value="type"
|
||||
no-library-only-props
|
||||
@input="e => type = e"
|
||||
>
|
||||
<dialog-base
|
||||
:override-back-button="back"
|
||||
<dialog-base>
|
||||
<template slot="toolbar">
|
||||
<v-toolbar-title class="mr-4">
|
||||
<template v-if="tab === 2">
|
||||
New
|
||||
</template>{{ typeName }}
|
||||
</v-toolbar-title>
|
||||
<v-spacer />
|
||||
<v-slide-x-reverse-transition hide-on-leave>
|
||||
<v-switch
|
||||
v-if="tab === 0"
|
||||
:input-value="showPropertyHelp"
|
||||
append-icon="mdi-help"
|
||||
hide-details
|
||||
flat
|
||||
@change="propertyHelpChanged"
|
||||
/>
|
||||
<text-field
|
||||
v-if="tab === 1"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
regular
|
||||
hide-details
|
||||
:value="searchValue"
|
||||
:debounce="400"
|
||||
@change="searchChanged"
|
||||
/>
|
||||
</v-slide-x-reverse-transition>
|
||||
</template>
|
||||
<v-tabs
|
||||
slot="toolbar-extension"
|
||||
v-model="tab"
|
||||
>
|
||||
<template slot="toolbar">
|
||||
<v-toolbar-title class="mr-4">
|
||||
<template v-if="customProperty">
|
||||
New
|
||||
</template>{{ typeName }}
|
||||
</v-toolbar-title>
|
||||
<v-slide-x-transition>
|
||||
<text-field
|
||||
v-if="!customProperty"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
regular
|
||||
hide-details
|
||||
:value="searchValue"
|
||||
:debounce="400"
|
||||
@change="searchChanged"
|
||||
/>
|
||||
</v-slide-x-transition>
|
||||
<v-scale-transition>
|
||||
<v-btn
|
||||
v-if="!customProperty"
|
||||
fab
|
||||
small
|
||||
elevation="0"
|
||||
class="mr-2"
|
||||
color="accent"
|
||||
@click="customProperty = true"
|
||||
<v-tab :disabled="!!forcedType">
|
||||
{{ typeName || 'Type' }}
|
||||
</v-tab>
|
||||
<v-tab :disabled="!type">
|
||||
Library
|
||||
</v-tab>
|
||||
<v-tab :disabled="!type">
|
||||
Create
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
<v-tabs-items
|
||||
slot="unwrapped-content"
|
||||
v-model="tab"
|
||||
>
|
||||
<v-tab-item :disabled="!!forcedType">
|
||||
<property-selector
|
||||
no-library-only-props
|
||||
:parent-type="parentDoc && parentDoc.type"
|
||||
@select="e => type = e"
|
||||
/>
|
||||
</v-tab-item>
|
||||
<v-tab-item :disabled="!type">
|
||||
<v-expansion-panels
|
||||
multiple
|
||||
inset
|
||||
>
|
||||
<v-expansion-panel
|
||||
v-for="libraryNode in libraryNodes"
|
||||
:key="libraryNode._id"
|
||||
:model="libraryNode"
|
||||
:data-id="libraryNode._id"
|
||||
>
|
||||
<v-icon>mdi-plus</v-icon>
|
||||
</v-btn>
|
||||
</v-scale-transition>
|
||||
</template>
|
||||
<v-slide-x-transition
|
||||
class="unwrapped-content"
|
||||
leave-absolute
|
||||
>
|
||||
<div
|
||||
v-if="customProperty"
|
||||
key="custom-property-form"
|
||||
<v-expansion-panel-header>
|
||||
<template #default="{ open }">
|
||||
<v-checkbox
|
||||
v-model="selectedNodeIds"
|
||||
class="my-0 py-0 mr-2 flex-grow-0"
|
||||
hide-details
|
||||
:value="libraryNode._id"
|
||||
:disabled="!selectedNodeIds.includes(libraryNode._id) &&
|
||||
selectedNodeIds.length >= 20"
|
||||
@click.stop
|
||||
/>
|
||||
<v-layout column>
|
||||
<tree-node-view :model="libraryNode" />
|
||||
<div class="text-caption">
|
||||
{{ libraryNames[libraryNode.ancestors[0].id ] }}
|
||||
</div>
|
||||
</v-layout>
|
||||
<template v-if="open">
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
icon
|
||||
class="flex-grow-0"
|
||||
@click.stop="openPropertyDetails(libraryNode._id)"
|
||||
>
|
||||
<v-icon>mdi-window-restore</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</template>
|
||||
</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<library-node-expansion-content :model="libraryNode" />
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
<v-layout
|
||||
justify-center
|
||||
>
|
||||
<v-fade-transition mode="out-in">
|
||||
<div
|
||||
v-if="currentLimit < countAll"
|
||||
class="layout justify-center align-stretch"
|
||||
>
|
||||
<v-btn
|
||||
v-if="currentLimit < countAll"
|
||||
key="load-more-btn"
|
||||
:loading="!$subReady.searchLibraryNodes"
|
||||
color="accent"
|
||||
class="ma-4"
|
||||
@click="loadMore"
|
||||
>
|
||||
Load More
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-fade-transition>
|
||||
</v-layout>
|
||||
</v-tab-item>
|
||||
<v-tab-item :disabled="!type">
|
||||
<v-card-text
|
||||
v-if="!$slots['unwrapped-content']"
|
||||
>
|
||||
<component
|
||||
:is="type"
|
||||
@@ -56,113 +133,43 @@
|
||||
@push="push"
|
||||
@pull="pull"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
key="library-search"
|
||||
>
|
||||
<v-expansion-panels
|
||||
multiple
|
||||
inset
|
||||
>
|
||||
<v-expansion-panel
|
||||
v-for="libraryNode in libraryNodes"
|
||||
:key="libraryNode._id"
|
||||
:model="libraryNode"
|
||||
:data-id="libraryNode._id"
|
||||
>
|
||||
<v-expansion-panel-header>
|
||||
<template #default="{ open }">
|
||||
<v-checkbox
|
||||
v-model="selectedNodeIds"
|
||||
class="my-0 py-0 mr-2"
|
||||
hide-details
|
||||
:value="libraryNode._id"
|
||||
:disabled="!selectedNodeIds.includes(libraryNode._id) &&
|
||||
selectedNodeIds.length >= 20"
|
||||
@click.stop
|
||||
/>
|
||||
<v-layout column>
|
||||
<tree-node-view :model="libraryNode" />
|
||||
<div class="text-caption">
|
||||
{{ libraryNames[libraryNode.ancestors[0].id ] }}
|
||||
</div>
|
||||
</v-layout>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
v-if="open"
|
||||
icon
|
||||
class="flex-grow-0"
|
||||
@click.stop="openPropertyDetails(libraryNode._id)"
|
||||
>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<library-node-expansion-content :model="libraryNode" />
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
<v-layout
|
||||
justify-center
|
||||
>
|
||||
<v-fade-transition mode="out-in">
|
||||
<div
|
||||
v-if="currentLimit < countAll"
|
||||
class="layout justify-center align-stretch"
|
||||
>
|
||||
<v-btn
|
||||
v-if="currentLimit < countAll"
|
||||
key="load-more-btn"
|
||||
:loading="!$subReady.searchLibraryNodes"
|
||||
color="accent"
|
||||
class="ma-4"
|
||||
@click="loadMore"
|
||||
>
|
||||
Load More
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-fade-transition>
|
||||
</v-layout>
|
||||
</div>
|
||||
</v-slide-x-transition>
|
||||
<template slot="actions">
|
||||
<v-btn
|
||||
text
|
||||
@click="$store.dispatch('popDialogStack')"
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
v-if="customProperty"
|
||||
text
|
||||
color="primary"
|
||||
:disabled="!valid"
|
||||
@click="$store.dispatch('popDialogStack', model)"
|
||||
>
|
||||
create
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-else
|
||||
text
|
||||
color="primary"
|
||||
:disabled="!selectedNodeIds.length"
|
||||
@click="$store.dispatch('popDialogStack', selectedNodeIds)"
|
||||
>
|
||||
<template v-if="selectedNodeIds.length >= 15">
|
||||
{{ selectedNodeIds.length }}/20
|
||||
</template>
|
||||
Insert
|
||||
</v-btn>
|
||||
</template>
|
||||
</dialog-base>
|
||||
</selectable-property-dialog>
|
||||
</v-card-text>
|
||||
</v-tab-item>
|
||||
</v-tabs-items>
|
||||
<template slot="actions">
|
||||
<v-btn
|
||||
text
|
||||
@click="$store.dispatch('popDialogStack')"
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
v-if="tab === 2"
|
||||
text
|
||||
color="primary"
|
||||
:disabled="!valid"
|
||||
@click="$store.dispatch('popDialogStack', model)"
|
||||
>
|
||||
create
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-else-if="tab === 1"
|
||||
text
|
||||
color="primary"
|
||||
:disabled="!selectedNodeIds.length"
|
||||
@click="$store.dispatch('popDialogStack', selectedNodeIds)"
|
||||
>
|
||||
<template v-if="selectedNodeIds.length >= 15">
|
||||
{{ selectedNodeIds.length }}/20
|
||||
</template>
|
||||
Insert
|
||||
</v-btn>
|
||||
</template>
|
||||
</dialog-base>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import SelectablePropertyDialog from '/imports/ui/properties/shared/SelectablePropertyDialog.vue';
|
||||
import LibraryNodes from '/imports/api/library/LibraryNodes.js';
|
||||
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
|
||||
import { getPropertyName } from '/imports/constants/PROPERTIES.js';
|
||||
@@ -172,14 +179,19 @@
|
||||
import propertyFormIndex from '/imports/ui/properties/forms/shared/propertyFormIndex.js';
|
||||
import propertySchemasIndex from '/imports/api/properties/propertySchemasIndex.js';
|
||||
import Libraries from '/imports/api/library/Libraries.js';
|
||||
import getThemeColor from '/imports/ui/utility/getThemeColor.js';
|
||||
import PropertySelector from '/imports/ui/properties/shared/PropertySelector.vue';
|
||||
import {snackbar} from '/imports/ui/components/snackbars/SnackbarQueue.js';
|
||||
|
||||
const SKIP_LIBRARY_PROP_TYPES = ['note', 'damage', 'adjustment']
|
||||
|
||||
export default {
|
||||
components: {
|
||||
...propertyFormIndex,
|
||||
SelectablePropertyDialog,
|
||||
PropertySelector,
|
||||
DialogBase,
|
||||
TreeNodeView,
|
||||
LibraryNodeExpansionContent,
|
||||
...propertyFormIndex,
|
||||
},
|
||||
mixins: [schemaFormMixin],
|
||||
props: {
|
||||
@@ -187,6 +199,10 @@
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
suggestedTypes: {
|
||||
type: Array,
|
||||
default: undefined,
|
||||
},
|
||||
suggestedType: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
@@ -207,13 +223,16 @@
|
||||
type: this.type,
|
||||
},
|
||||
searchValue: undefined,
|
||||
customProperty: false,
|
||||
debounceTime: 0,
|
||||
tab: 0,
|
||||
};},
|
||||
computed: {
|
||||
typeName(){
|
||||
return getPropertyName(this.type) || 'Property';
|
||||
},
|
||||
toolbarColor(){
|
||||
return getThemeColor('secondary');
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
type(newType){
|
||||
@@ -224,14 +243,18 @@
|
||||
this.changeType(this.type);
|
||||
},
|
||||
methods: {
|
||||
back(){
|
||||
if (this.customProperty){
|
||||
this.customProperty = false;
|
||||
} else if (this.forcedType){
|
||||
this.$store.dispatch('popDialogStack');
|
||||
} else {
|
||||
this.type = undefined;
|
||||
}
|
||||
|
||||
propertyHelpChanged(value){
|
||||
Meteor.users.setPreference.call({
|
||||
preference: 'hidePropertySelectDialogHelp',
|
||||
value: !value
|
||||
}, error => {
|
||||
if (!error) return;
|
||||
console.error(error);
|
||||
snackbar({
|
||||
text: error.reason,
|
||||
});
|
||||
});
|
||||
},
|
||||
searchChanged(val, ack){
|
||||
this._subs.searchLibraryNodes.setData('searchTerm', val);
|
||||
@@ -251,6 +274,11 @@
|
||||
changeType(type){
|
||||
this._subs.searchLibraryNodes.setData('type', type);
|
||||
if (!type) return;
|
||||
if (SKIP_LIBRARY_PROP_TYPES.includes(type)){
|
||||
this.tab = 2;
|
||||
} else {
|
||||
this.tab = 1;
|
||||
}
|
||||
this.schema = propertySchemasIndex[type];
|
||||
this.validationContext = this.schema.newContext();
|
||||
let model = this.schema.clean({});
|
||||
@@ -265,12 +293,16 @@
|
||||
_id: id,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
'$subscribe':{
|
||||
'searchLibraryNodes': [],
|
||||
},
|
||||
showPropertyHelp(){
|
||||
let user = Meteor.user();
|
||||
return !(user?.preferences?.hidePropertySelectDialogHelp)
|
||||
},
|
||||
currentLimit(){
|
||||
return this._subs.searchLibraryNodes.data('limit') || 32;
|
||||
},
|
||||
|
||||
@@ -98,6 +98,7 @@ import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
|
||||
import { getHighestOrder } from '/imports/api/parenting/order.js';
|
||||
import insertProperty from '/imports/api/creature/creatureProperties/methods/insertProperty.js';
|
||||
import Breadcrumbs from '/imports/ui/creature/creatureProperties/Breadcrumbs.vue';
|
||||
import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js';
|
||||
|
||||
let formIndex = {};
|
||||
for (let key in propertyFormIndex){
|
||||
@@ -234,8 +235,7 @@ export default {
|
||||
},
|
||||
});
|
||||
},
|
||||
selectSubProperty(doc){
|
||||
let _id = doc && doc._id
|
||||
selectSubProperty(_id){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `tree-node-${_id}`,
|
||||
@@ -244,28 +244,37 @@ export default {
|
||||
},
|
||||
addProperty(){
|
||||
let parentPropertyId = this.model._id;
|
||||
// Open the dialog to insert the property
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-creation-dialog',
|
||||
component: 'add-creature-property-dialog',
|
||||
elementId: 'insert-creature-property-btn',
|
||||
callback(creatureProperty){
|
||||
if (!creatureProperty) return;
|
||||
// Get order and parent
|
||||
data: {
|
||||
parentDoc: this.model,
|
||||
},
|
||||
callback(result){
|
||||
if (!result) return;
|
||||
let parentRef = {
|
||||
id: parentPropertyId,
|
||||
collection: 'creatureProperties',
|
||||
};
|
||||
creatureProperty.order = getHighestOrder({
|
||||
let order = getHighestOrder({
|
||||
collection: CreatureProperties,
|
||||
ancestorId: parentRef.id,
|
||||
}) + 0.5;
|
||||
|
||||
// Insert the property
|
||||
let id = insertProperty.call({creatureProperty, parentRef});
|
||||
return `tree-node-${id}`;
|
||||
if (Array.isArray(result)){
|
||||
let nodeIds = result;
|
||||
let id = insertPropertyFromLibraryNode.call({nodeIds, parentRef, order});
|
||||
return `tree-node-${id}`;
|
||||
} else {
|
||||
let creatureProperty = result;
|
||||
// Get order and parent
|
||||
creatureProperty.order = order;
|
||||
// Insert the property
|
||||
let id = insertProperty.call({creatureProperty, parentRef});
|
||||
return `tree-node-${id}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -21,19 +21,25 @@
|
||||
<v-icon>mdi-arrow-left</v-icon>
|
||||
</v-btn>
|
||||
<slot name="toolbar" />
|
||||
<slot
|
||||
slot="extension"
|
||||
name="toolbar-extension"
|
||||
/>
|
||||
</v-toolbar>
|
||||
</slot>
|
||||
<div
|
||||
v-if="$slots['unwrapped-content']"
|
||||
id="base-dialog-body"
|
||||
class="unwrapped-content"
|
||||
@scroll.passive="onScroll"
|
||||
>
|
||||
<slot name="unwrapped-content" />
|
||||
</div>
|
||||
<v-card-text
|
||||
v-if="!$slots['unwrapped-content']"
|
||||
v-else
|
||||
id="base-dialog-body"
|
||||
v-scroll:#base-dialog-body="onScroll"
|
||||
:class="{'dark-body': darkBody}"
|
||||
@scroll.passive="onScroll"
|
||||
>
|
||||
<slot />
|
||||
</v-card-text>
|
||||
@@ -90,7 +96,7 @@
|
||||
|
||||
<style scoped>
|
||||
.base-dialog-toolbar {
|
||||
z-index: 1;
|
||||
z-index: 2;
|
||||
border-radius: 2px 2px 0 0;
|
||||
}
|
||||
#base-dialog-body, .unwrapped-content {
|
||||
|
||||
57
app/imports/ui/properties/shared/PropertySelectCard.vue
Normal file
57
app/imports/ui/properties/shared/PropertySelectCard.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<template lang="html">
|
||||
<v-card
|
||||
hover
|
||||
style="height: 100%; overflow: hidden;"
|
||||
@click="e => $emit('click', e)"
|
||||
>
|
||||
<v-card-title
|
||||
class="subtitle pb-3"
|
||||
style="text-align: center;"
|
||||
>
|
||||
<v-avatar tile>
|
||||
<v-icon x-large>
|
||||
{{ property.icon }}
|
||||
</v-icon>
|
||||
</v-avatar>
|
||||
<span class="ml-3">
|
||||
{{ property.name }}
|
||||
</span>
|
||||
</v-card-title>
|
||||
<v-expand-transition>
|
||||
<div
|
||||
v-if="showPropertyHelp"
|
||||
class="mx-4"
|
||||
>
|
||||
{{ property.helpText }}
|
||||
<div style="height: 16px;" />
|
||||
<div
|
||||
v-if="property.examples"
|
||||
class="text-caption"
|
||||
>
|
||||
{{ property.examples }}
|
||||
<div style="height: 16px;" />
|
||||
</div>
|
||||
</div>
|
||||
</v-expand-transition>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
export default {
|
||||
props: {
|
||||
property: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
meteor: {
|
||||
showPropertyHelp(){
|
||||
let user = Meteor.user();
|
||||
return !(user?.preferences?.hidePropertySelectDialogHelp)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -2,77 +2,113 @@
|
||||
<div class="card-raised-background">
|
||||
<v-container
|
||||
fluid
|
||||
grid-list-lg
|
||||
fill-height
|
||||
>
|
||||
<v-layout
|
||||
<v-row
|
||||
wrap
|
||||
fill-height
|
||||
dense
|
||||
justify="center"
|
||||
justify-sm="start"
|
||||
>
|
||||
<template v-for="(property, type) in PROPERTIES">
|
||||
<v-flex
|
||||
<template v-if="properties.suggested">
|
||||
<v-col
|
||||
cols="12"
|
||||
>
|
||||
<v-subheader>
|
||||
Suggested
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<template v-for="(property, type) in properties.suggested">
|
||||
<v-col
|
||||
v-if="!noLibraryOnlyProps || !property.libraryOnly"
|
||||
:key="type"
|
||||
md="4"
|
||||
sm="6"
|
||||
cols="10"
|
||||
>
|
||||
<property-select-card
|
||||
:property="property"
|
||||
@click="$emit('select', type)"
|
||||
/>
|
||||
</v-col>
|
||||
</template>
|
||||
</template>
|
||||
<v-col
|
||||
v-if="properties.suggested"
|
||||
cols="12"
|
||||
>
|
||||
<v-subheader>
|
||||
More
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<template v-for="(property, type) in properties.more">
|
||||
<v-col
|
||||
v-if="!noLibraryOnlyProps || !property.libraryOnly"
|
||||
:key="type"
|
||||
md4
|
||||
sm6
|
||||
xs12
|
||||
md="4"
|
||||
sm="6"
|
||||
cols="10"
|
||||
>
|
||||
<v-card
|
||||
hover
|
||||
style="height: 100%; overflow: hidden;"
|
||||
<property-select-card
|
||||
:property="property"
|
||||
@click="$emit('select', type)"
|
||||
>
|
||||
<v-card-title
|
||||
class="subtitle pb-3"
|
||||
style="text-align: center;"
|
||||
>
|
||||
<v-avatar tile>
|
||||
<v-icon x-large>
|
||||
{{ property.icon }}
|
||||
</v-icon>
|
||||
</v-avatar>
|
||||
<span class="ml-3">
|
||||
{{ property.name }}
|
||||
</span>
|
||||
</v-card-title>
|
||||
<v-expand-transition>
|
||||
<div
|
||||
v-if="showPropertyHelp"
|
||||
class="mx-4"
|
||||
>
|
||||
{{ property.helpText }}
|
||||
<div style="height: 16px;" />
|
||||
<div
|
||||
v-if="property.examples"
|
||||
class="text-caption"
|
||||
>
|
||||
{{ property.examples }}
|
||||
<div style="height: 16px;" />
|
||||
</div>
|
||||
</div>
|
||||
</v-expand-transition>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
/>
|
||||
</v-col>
|
||||
</template>
|
||||
</v-layout>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import PROPERTIES from '/imports/constants/PROPERTIES.js';
|
||||
|
||||
import PropertySelectCard from '/imports/ui/properties/shared/PropertySelectCard.vue';
|
||||
export default {
|
||||
components: {
|
||||
PropertySelectCard,
|
||||
},
|
||||
props: {
|
||||
noLibraryOnlyProps: Boolean,
|
||||
parentType: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
suggestedTypes: {
|
||||
type: Array,
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
data(){ return {
|
||||
PROPERTIES,
|
||||
};},
|
||||
meteor: {
|
||||
showPropertyHelp(){
|
||||
let user = Meteor.user();
|
||||
return !(user?.preferences?.hidePropertySelectDialogHelp)
|
||||
computed:{
|
||||
properties(){
|
||||
let suggested;
|
||||
let more = {};
|
||||
if (this.suggestedTypes){
|
||||
for (const key in PROPERTIES){
|
||||
let prop = PROPERTIES[key];
|
||||
if (this.suggestedTypes.includes(prop.type)){
|
||||
if (!suggested) suggested = {};
|
||||
suggested[key] = prop;
|
||||
} else {
|
||||
more[key] = prop;
|
||||
}
|
||||
}
|
||||
return {suggested, more};
|
||||
} else if (this.parentType) {
|
||||
for (const key in PROPERTIES){
|
||||
let prop = PROPERTIES[key];
|
||||
if (prop.suggestedParents.includes(this.parentType)){
|
||||
if (!suggested) suggested = {};
|
||||
suggested[key] = prop;
|
||||
} else {
|
||||
more[key] = prop;
|
||||
}
|
||||
}
|
||||
return {suggested, more};
|
||||
} else {
|
||||
return {more: PROPERTIES};
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
<property-selector
|
||||
slot="unwrapped-content"
|
||||
:no-library-only-props="noLibraryOnlyProps"
|
||||
:parent-type="parentType"
|
||||
@select="type => $emit('input', type)"
|
||||
/>
|
||||
</dialog-base>
|
||||
@@ -49,7 +50,12 @@ export default {
|
||||
noLibraryOnlyProps: Boolean,
|
||||
value: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
parentType: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
showPropertyHelp(){
|
||||
|
||||
Reference in New Issue
Block a user