Made big improvements to library page in preparation of adding library nodes to character sheets

This commit is contained in:
Stefan Zermatten
2019-11-04 13:27:31 +02:00
parent f4d613a20b
commit f6d80f6ae4
13 changed files with 345 additions and 210 deletions

View File

@@ -21,7 +21,7 @@
<v-content v-if="$subReady.singleCharacter">
<v-tabs-items v-model="tab">
<v-tab-item>
<tree-tab :character-id="creatureId"/>
<tree-tab :creature-id="creatureId"/>
</v-tab-item>
</v-tabs-items>
</v-content>

View File

@@ -35,13 +35,46 @@
</v-card-text>
</div>
</v-card>
<v-btn fixed fab bottom right
color="primary"
@click="insertCreatureProperty"
data-id="insert-creature-property-fab"
>
<v-icon>add</v-icon>
</v-btn>
<v-speed-dial
v-model="fab"
fixed
bottom="bottom"
right="right"
>
<template v-slot:activator>
<v-btn
v-model="fab"
color="primary"
fab
data-id="insert-creature-property-fab"
>
<v-icon>add</v-icon>
<v-icon>close</v-icon>
</v-btn>
</template>
<v-tooltip disabled left :value="true" :nudge-left="16">
Property from library
<v-btn
slot="activator"
color="primary"
small fab
@click="propertyFromLibrary"
>
<v-icon>book</v-icon>
</v-btn>
</v-tooltip>
<v-tooltip disabled left :value="true" :nudge-left="16">
New property
<v-btn
slot="activator"
color="primary"
small fab
@click="insertCreatureProperty"
>
<v-icon>edit</v-icon>
</v-btn>
</v-tooltip>
</v-speed-dial>
</div>
</template>
@@ -62,6 +95,7 @@
data(){ return {
organize: false,
selected: undefined,
fab: false,
};},
props: {
creatureId: {
@@ -84,6 +118,17 @@
}
});
},
propertyFromLibrary(){
let that = this;
this.$store.commit('pushDialogStack', {
component: 'creature-property-from-library-dialog',
elementId: 'insert-creature-property-fab',
callback(creatureProperty){
console.log(creatureProperty);
return;
}
});
},
editCreatureProperty(){
let that = this;
this.$store.commit('pushDialogStack', {

View File

@@ -0,0 +1,35 @@
<template lang="html">
<dialog-base>
<div slot="toolbar">Add from library</div>
<library-and-node
slot="unwrapped-content"
@selected="val => node = val"
style="height: 100%;"
/>
<template slot="actions">
<v-spacer/>
<v-btn
flat
@click="$store.dispatch('popDialogStack', node)"
color="primary"
>Insert</v-btn>
</template>
</dialog-base>
</template>
<script>
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
import LibraryAndNode from '/imports/ui/library/LibraryAndNode.vue';
export default {
components: {
DialogBase,
LibraryAndNode,
},
data(){return {
node: undefined,
};},
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -20,8 +20,17 @@
example > bread > crumb
</v-card-text>
</template>
<slot name="unwrapped-content"/>
<v-card-text id="base-dialog-body" v-scroll:#base-dialog-body="onScroll">
<div
v-if="$slots['unwrapped-content']"
class="unwrapped-content"
>
<slot name="unwrapped-content"/>
</div>
<v-card-text
v-if="!$slots['unwrapped-content']"
id="base-dialog-body"
v-scroll:#base-dialog-body="onScroll"
>
<v-tabs-items :value="isEditing ? 1 : 0" touchless>
<v-tab-item>
<slot/>
@@ -32,7 +41,7 @@
</v-tabs-items>
</v-card-text>
<v-card-actions>
<slot name="actions"></slot>
<slot name="actions"/>
</v-card-actions>
</v-layout>
</template>
@@ -73,7 +82,7 @@
z-index: 1;
border-radius: 2px 2px 0 0;
}
#base-dialog-body {
#base-dialog-body, .unwrapped-content {
flex-grow: 1;
overflow: auto;
}

View File

@@ -2,6 +2,7 @@ import AttributeDialog from '/imports/ui/properties/attributes/AttributeDialog.v
import AttributeDialogContainer from '/imports/ui/properties/attributes/AttributeDialogContainer.vue';
import AttributeCreationDialog from '/imports/ui/properties/attributes/AttributeCreationDialog.vue';
import CreaturePropertyCreationDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyCreationDialog.vue';
import CreaturePropertyFromLibraryDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyFromLibraryDialog.vue'
import FeatureCreationDialog from '/imports/ui/properties/features/FeatureCreationDialog.vue';
import FeatureDialogContainer from '/imports/ui/properties/features/FeatureDialogContainer.vue';
import LibraryCreationDialog from '/imports/ui/library/LibraryCreationDialog.vue';
@@ -14,6 +15,7 @@ export default {
AttributeDialogContainer,
AttributeCreationDialog,
CreaturePropertyCreationDialog,
CreaturePropertyFromLibraryDialog,
FeatureCreationDialog,
FeatureDialogContainer,
LibraryCreationDialog,

View File

@@ -98,7 +98,7 @@
let links = [
{title: "Home", icon: "home", to: "/"},
{title: "Creatures", icon: "group", to: "/characterList", vif: Meteor.userId()},
{title: "Libraries", icon: "book", to: "/library", vif: Meteor.userId()},
{title: "Library", icon: "book", to: "/library", vif: Meteor.userId()},
{title: "Send Feedback", icon: "bug_report", to: "/feedback"},
{title: "Patreon", icon: "", href: "https://www.patreon.com/dicecloud"},
{title: "Github", icon: "", href: "https://github.com/ThaumRystra/DiceCloud/tree/version-2"},

View File

@@ -0,0 +1,94 @@
<template lang="html">
<div class="layout row" style="background-color: inherit;">
<div class="layout column" style="background-color: inherit;">
<v-toolbar dense flat>
<v-spacer/>
<v-switch
label="Organize"
class="mx-3"
v-model="organize"
style="flex-grow: 0; height: 32px;"
/>
</v-toolbar>
<library-browser
edit-mode
:organize-mode="organize"
:selected-node-id="selected"
@selected="e => selected = e"
/>
</div>
<v-divider vertical/>
<div style="width: 100%; background-color: inherit;" data-id="selected-node-card">
<v-toolbar dense flat>
<property-icon :type="selectedNode && selectedNode.type" class="mr-2"/>
<div class="title">
{{getPropertyName(selectedNode && selectedNode.type)}}
</div>
<v-spacer/>
<v-btn flat icon @click="editLibraryNode" v-if="selectedNode">
<v-icon>create</v-icon>
</v-btn>
</v-toolbar>
<v-card-text style="overflow-y: auto;">
<property-viewer :model="selectedNode"/>
</v-card-text>
</div>
</div>
</template>
<script>
import ToolbarLayout from '/imports/ui/layouts/ToolbarLayout.vue';
import LibraryBrowser from '/imports/ui/library/LibraryBrowser.vue';
import PropertyViewer from '/imports/ui/properties/PropertyViewer.vue';
import LibraryNodes, { insertNode } from '/imports/api/library/LibraryNodes.js';
import Libraries from '/imports/api/library/Libraries.js';
import PropertyIcon from '/imports/ui/properties/PropertyIcon.vue';
import { getPropertyName } from '/imports/constants/PROPERTIES.js';
export default {
components: {
LibraryBrowser,
ToolbarLayout,
PropertyViewer,
PropertyIcon,
},
data(){ return {
organize: false,
selected: undefined,
};},
watch:{
selectedNode(val){
this.$emit('selected', val)
},
},
methods: {
editLibraryNode(){
this.$store.commit('pushDialogStack', {
component: 'library-node-edit-dialog',
elementId: 'selected-node-card',
data: {_id: this.selected},
});
},
getPropertyName,
},
meteor: {
$subscribe: {
'libraries': [],
},
libraries(){
return Libraries.find({}, {
sort: {name: 1}
}).fetch();
},
selectedNode(){
return LibraryNodes.findOne({
_id: this.selected,
removed: {$ne: true}
});
}
}
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -0,0 +1,122 @@
<template lang="html">
<div
style="
background-color: inherit;
overflow-y: auto;
width: initial;
max-width: 100%;
min-width: 320px;
"
>
<v-expansion-panel
style="box-shadow: none;"
v-model="expandedLibrary"
>
<v-expansion-panel-content
lazy
v-for="library in libraries"
:key="library._id"
:data-id="library._id"
>
<template v-slot:header>
<div class="title">{{library.name}}</div>
</template>
<v-card flat>
<library-contents-container
:library-id="library._id"
:organize-mode="organizeMode"
:edit-mode="editMode"
@selected="e => $emit('selected', e)"
:selected-node-id="selectedNodeId"
/>
<v-card-actions>
<v-spacer/>
<v-btn
flat
color="primary"
style="background-color: inherit; margin-top: 0;"
@click="insertLibraryNode(library._id)"
:data-id="`insert-node-${library._id}`"
>
<v-icon>add</v-icon>
New property
</v-btn>
</v-card-actions>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
<v-btn
v-show="expandedLibrary === null"
v-if="editMode"
flat
color="primary"
style="background-color: inherit;"
@click="insertLibrary"
data-id="insert-library-button"
>
<v-icon>add</v-icon>
New library
</v-btn>
</div>
</template>
<script>
import LibraryContentsContainer from '/imports/ui/library/LibraryContentsContainer.vue';
import { setDocToLastOrder } from '/imports/api/parenting/order.js';
import LibraryNodes, { insertNode } from '/imports/api/library/LibraryNodes.js';
import Libraries, { insertLibrary } from '/imports/api/library/Libraries.js';
export default {
components: {
LibraryContentsContainer,
},
props: {
organizeMode: Boolean,
editMode: Boolean,
selectedNodeId: String,
},
data(){ return {
expandedLibrary: null,
};},
meteor: {
$subscribe: {
'libraries': [],
},
libraries(){
return Libraries.find({}, {
sort: {name: 1}
}).fetch();
},
},
methods: {
insertLibrary(){
this.$store.commit('pushDialogStack', {
component: 'library-creation-dialog',
elementId: 'insert-library-button',
callback(library){
if (!library) return;
let libraryId = insertLibrary.call(library);
return libraryId;
}
});
},
insertLibraryNode(libraryId){
this.$store.commit('pushDialogStack', {
component: 'library-node-creation-dialog',
elementId: `insert-node-${libraryId}`,
callback(libraryNode){
if (!libraryNode) return;
libraryNode.parent = {collection: "libraries", id: libraryId};
libraryNode.ancestors = [ {collection: "libraries", id: libraryId}];
setDocToLastOrder({collection: LibraryNodes, doc: libraryNode});
let libraryNodeId = insertNode.call(libraryNode);
return libraryNodeId;
}
});
},
}
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,16 +1,14 @@
<template lang="html">
<v-card-text style="width: initial; max-width: 100%; min-width: 320px;">
<tree-node-list
v-if="libraryChildren"
:children="libraryChildren"
:group="library && library._id"
:organize="organize"
:selected-node-id="selectedNodeId"
@selected="e => $emit('selected', e)"
@reordered="reordered"
@reorganized="reorganized"
/>
</v-card-text>
<tree-node-list
:children="libraryChildren"
:group="library && library._id"
:organize="organizeMode"
:selected-node-id="selectedNodeId"
@selected="e => $emit('selected', e)"
@reordered="reordered"
@reorganized="reorganized"
/>
</template>
<script>
@@ -26,12 +24,14 @@
},
props: {
libraryId: String,
organize: Boolean,
organizeMode: Boolean,
selectedNodeId: String,
},
meteor: {
$subscribe: {
'library': [this.libraryId],
'library'(){
return [this.libraryId]
},
},
library(){
return Libraries.findOne(this.libraryId);

View File

@@ -1,71 +0,0 @@
<template lang="html">
<toolbar-layout>
<span slot="toolbar">Libraries</span>
<v-card class="ma-4">
<v-list v-if="libraries.length">
<v-list-tile
v-for="library in libraries"
:key="library._id"
:to="`/library/${library._id}`"
:data-id="library._id"
>
<v-list-tile-content>
<v-list-tile-title>
{{library.name}}
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
<v-card-text v-else-if="$subReady.libraries">
You aren't subscribed to any libraries :O
</v-card-text>
<v-card-text v-if="!$subReady.libraries" class="layout row justify-center">
<v-progress-circular indeterminate/>
</v-card-text>
</v-card>
<v-btn fixed fab bottom right
color="primary"
@click="insertLibrary"
data-id="insert-library-fab"
>
<v-icon>add</v-icon>
</v-btn>
</toolbar-layout>
</template>
<script>
import ToolbarLayout from '/imports/ui/layouts/ToolbarLayout.vue';
import Libraries, {insertLibrary} from '/imports/api/library/Libraries.js';
export default {
components: {
ToolbarLayout,
},
methods: {
insertLibrary(){
this.$store.commit('pushDialogStack', {
component: 'library-creation-dialog',
elementId: 'insert-library-fab',
callback(library){
if (!library) return;
let libraryId = insertLibrary.call(library);
return libraryId;
}
});
},
},
meteor: {
$subscribe: {
'libraries': [],
},
libraries(){
return Libraries.find({}, {
sort: {name: 1}
}).fetch();
}
}
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,119 +1,21 @@
<template lang="html">
<toolbar-layout>
<template slot="toolbar">
<v-btn icon flat to="/library" active-class="">
<v-icon>arrow_back</v-icon>
</v-btn>
{{library && library.name || 'Library'}}
<v-spacer/>
Libraries
</template>
<v-card class="ma-4 layout row" data-id="library-card">
<div>
<v-toolbar dense flat>
<v-spacer/>
<v-switch
label="Organize"
class="mx-3"
v-model="organize"
style="flex-grow: 0; height: 32px;"
/>
</v-toolbar>
<library-contents-container
:library-id="$route.params.id"
:organize="organize"
@selected="e => selected = e"
:selected-node-id="selected"
/>
</div>
<v-divider vertical/>
<div style="width: 100%; background-color: inherit;" data-id="selected-node-card">
<v-toolbar dense flat>
<property-icon :type="selectedNode && selectedNode.type" class="mr-2"/>
<div class="title">
{{getPropertyName(selectedNode && selectedNode.type)}}
</div>
<v-spacer/>
<v-btn flat icon @click="editLibraryNode" v-if="selectedNode">
<v-icon>create</v-icon>
</v-btn>
</v-toolbar>
<v-card-text>
<property-viewer :model="selectedNode"/>
</v-card-text>
</div>
<v-card class="ma-4">
<library-and-node/>
</v-card>
<v-btn fixed fab bottom right
color="primary"
@click="insertLibraryNode"
data-id="insert-library-node-fab"
>
<v-icon>add</v-icon>
</v-btn>
</toolbar-layout>
</template>
<script>
import ToolbarLayout from '/imports/ui/layouts/ToolbarLayout.vue';
import LibraryContentsContainer from '/imports/ui/library/LibraryContentsContainer.vue';
import PropertyViewer from '/imports/ui/properties/PropertyViewer.vue';
import LibraryNodes, { insertNode } from '/imports/api/library/LibraryNodes.js';
import Libraries from '/imports/api/library/Libraries.js';
import { setDocToLastOrder } from '/imports/api/parenting/order.js';
import PropertyIcon from '/imports/ui/properties/PropertyIcon.vue';
import { getPropertyName } from '/imports/constants/PROPERTIES.js';
import LibraryAndNode from '/imports/ui/library/LibraryAndNode.vue';
export default {
components: {
ToolbarLayout,
LibraryContentsContainer,
PropertyViewer,
PropertyIcon,
LibraryAndNode,
},
data(){ return {
organize: false,
selected: undefined,
};},
methods: {
insertLibraryNode(){
let that = this;
this.$store.commit('pushDialogStack', {
component: 'library-node-creation-dialog',
elementId: 'insert-library-node-fab',
callback(libraryNode){
if (!libraryNode) return;
libraryNode.parent = {collection: "libraries", id: that.library._id};
libraryNode.ancestors = [ {collection: "libraries", id: that.library._id}];
setDocToLastOrder({collection: LibraryNodes, doc: libraryNode});
let libraryNodeId = insertNode.call(libraryNode);
return libraryNodeId;
}
});
},
editLibraryNode(){
let that = this;
this.$store.commit('pushDialogStack', {
component: 'library-node-edit-dialog',
elementId: 'selected-node-card',
data: {_id: this.selected},
});
},
getPropertyName,
},
meteor: {
$subscribe: {
library(){
return [this.$route.params.id];
},
},
library(){
return Libraries.findOne(this.$route.params.id);
},
selectedNode(){
return LibraryNodes.findOne({
_id: this.selected,
removed: {$ne: true}
});
}
}
};
</script>

View File

@@ -4,7 +4,6 @@ import Vue from 'vue';
// Components
import Home from '/imports/ui/pages/Home.vue';
import CharacterList from '/imports/ui/pages/CharacterList.vue';
import Libraries from '/imports/ui/pages/Libraries.vue';
import Library from '/imports/ui/pages/Library.vue';
import CharacterSheetPage from '/imports/ui/pages/CharacterSheetPage.vue';
import SignIn from '/imports/ui/pages/SignIn.vue' ;
@@ -22,7 +21,6 @@ const routerFactory = new RouterFactory({
scrollBehavior: nativeScrollBehavior,
});
RouterFactory.configure(factory => {
factory.addRoutes([
{
@@ -34,17 +32,16 @@ RouterFactory.configure(factory => {
component: CharacterList,
},{
path: '/library',
component: Libraries,
},{
path: '/library/:id',
component: Library,
},{
path: '/character/:id/:urlName',
component: CharacterSheetPage,
//component: NotImplemented,
//component: CharacterSheetPage,
component: NotImplemented,
},{
path: '/character/:id',
component: CharacterSheetPage,
//component: CharacterSheetPage,
component: NotImplemented,
},{
path: '/sign-in',
component: SignIn,

View File

@@ -1,3 +1,3 @@
.v-speed-dial__list{
margin-bottom: 12px;
padding-bottom: 12px;
}