Reworked single page libraries to be more in line with the library view
This commit is contained in:
@@ -25,8 +25,26 @@ Meteor.publish('libraries', function(){
|
||||
{owner: this.userId},
|
||||
{writers: this.userId},
|
||||
{readers: this.userId},
|
||||
{_id: {$in: subs}},
|
||||
{ _id: {$in: subs}, public: true },
|
||||
]
|
||||
}, {
|
||||
sort: {name: 1}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Meteor.publish('library', function(libraryId){
|
||||
if (!libraryId) return [];
|
||||
libraryIdSchema.validate({libraryId});
|
||||
this.autorun(function (){
|
||||
let userId = this.userId;
|
||||
let library = Libraries.findOne(libraryId);
|
||||
try { assertViewPermission(library, userId) }
|
||||
catch(e){
|
||||
return this.error(e);
|
||||
}
|
||||
return Libraries.find({
|
||||
_id: libraryId,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,13 +19,27 @@
|
||||
>
|
||||
<v-spacer />
|
||||
<v-switch
|
||||
v-if="!$route.params.id || canEditLibrary"
|
||||
v-model="organize"
|
||||
label="Organize"
|
||||
class="mx-3"
|
||||
style="flex-grow: 0; height: 32px;"
|
||||
/>
|
||||
</v-toolbar>
|
||||
<div
|
||||
v-if="$route.params.id"
|
||||
style="width: 100%; height: 100%; overflow: auto;"
|
||||
>
|
||||
<library-contents-container
|
||||
:library-id="$route.params.id"
|
||||
:organize-mode="organize"
|
||||
:selected-node-id="selected"
|
||||
should-subscribe
|
||||
@selected="clickNode"
|
||||
/>
|
||||
</div>
|
||||
<library-browser
|
||||
v-else
|
||||
edit-mode
|
||||
:organize-mode="organize"
|
||||
:selected-node-id="selected"
|
||||
@@ -53,14 +67,17 @@ import LibraryBrowser from '/imports/ui/library/LibraryBrowser.vue';
|
||||
import LibraryNodeDialog from '/imports/ui/library/LibraryNodeDialog.vue';
|
||||
import LibraryNodes from '/imports/api/library/LibraryNodes.js';
|
||||
import Libraries from '/imports/api/library/Libraries.js';
|
||||
import LibraryContentsContainer from '/imports/ui/library/LibraryContentsContainer.vue';
|
||||
import { getPropertyName } from '/imports/constants/PROPERTIES.js';
|
||||
import isDarkColor from '/imports/ui/utility/isDarkColor.js';
|
||||
import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TreeDetailLayout,
|
||||
LibraryBrowser,
|
||||
LibraryNodeDialog,
|
||||
LibraryContentsContainer,
|
||||
},
|
||||
props: {
|
||||
selection: Boolean,
|
||||
@@ -112,11 +129,34 @@ export default {
|
||||
getPropertyName,
|
||||
},
|
||||
meteor: {
|
||||
$subscribe: {
|
||||
'library'(){
|
||||
if (this.$route.params.id){
|
||||
return [this.$route.params.id];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
},
|
||||
libraries(){
|
||||
return Libraries.find({}, {
|
||||
sort: {name: 1}
|
||||
}).fetch();
|
||||
},
|
||||
library(){
|
||||
let libraryId = this.$route.params.id;
|
||||
if (!libraryId) return;
|
||||
return Libraries.findOne(libraryId);
|
||||
},
|
||||
canEditLibrary(){
|
||||
if (!this.$route.params.id) return;
|
||||
try {
|
||||
assertEditPermission(this.library, Meteor.userId());
|
||||
return true;
|
||||
} catch (e){
|
||||
return false;
|
||||
}
|
||||
},
|
||||
selectedNode(){
|
||||
return LibraryNodes.findOne({
|
||||
_id: this.selected,
|
||||
|
||||
@@ -24,10 +24,10 @@
|
||||
<v-card flat>
|
||||
<library-contents-container
|
||||
:library-id="library._id"
|
||||
:organize-mode="organizeMode"
|
||||
:organize-mode="organizeMode && editPermission(library)"
|
||||
:edit-mode="editMode"
|
||||
:selected-node-id="selectedNodeId"
|
||||
:should-subscribe="isExpanded(index)"
|
||||
:should-subscribe="expandedLibrary[index]"
|
||||
@selected="e => $emit('selected', e)"
|
||||
/>
|
||||
<v-card-actions>
|
||||
@@ -48,9 +48,9 @@
|
||||
small
|
||||
icon
|
||||
:disabled="!editPermission(library)"
|
||||
@click="editLibrary(library._id)"
|
||||
@click="$router.push(`/library/${library._id}`)"
|
||||
>
|
||||
<v-icon>create</v-icon>
|
||||
<v-icon>arrow_forward</v-icon>
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
@@ -90,7 +90,7 @@ export default {
|
||||
selectedNodeId: String,
|
||||
},
|
||||
data(){ return {
|
||||
expandedLibrary: null,
|
||||
expandedLibrary: [],
|
||||
};},
|
||||
meteor: {
|
||||
$subscribe: {
|
||||
@@ -117,9 +117,7 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isExpanded(index){
|
||||
return this.expandedLibrary && this.expandedLibrary[index];
|
||||
},
|
||||
log: console.log,
|
||||
insertLibrary(){
|
||||
if (this.paidBenefits){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
|
||||
@@ -1,20 +1,30 @@
|
||||
<template lang="html">
|
||||
<tree-node-list
|
||||
v-if="$subReady.libraryNodes"
|
||||
group="library"
|
||||
:children="libraryChildren"
|
||||
:organize="organizeMode"
|
||||
:selected-node-id="selectedNodeId"
|
||||
@selected="e => $emit('selected', e)"
|
||||
@reordered="reordered"
|
||||
@reorganized="reorganized"
|
||||
/>
|
||||
<v-progress-circular
|
||||
v-else
|
||||
color="primary"
|
||||
indeterminate
|
||||
style="width: 95%;"
|
||||
/>
|
||||
<v-fade-transition
|
||||
hide-on-leave
|
||||
>
|
||||
<tree-node-list
|
||||
v-if="slowShouldSubscribe && $subReady.libraryNodes"
|
||||
group="library"
|
||||
:children="libraryChildren"
|
||||
:organize="organizeMode"
|
||||
:selected-node-id="selectedNodeId"
|
||||
@selected="e => $emit('selected', e)"
|
||||
@reordered="reordered"
|
||||
@reorganized="reorganized"
|
||||
/>
|
||||
<v-layout
|
||||
v-else
|
||||
row
|
||||
align-center
|
||||
justify-center
|
||||
style="width: 100%;"
|
||||
>
|
||||
<v-progress-circular
|
||||
color="primary"
|
||||
:indeterminate="slowShouldSubscribe"
|
||||
/>
|
||||
</v-layout>
|
||||
</v-fade-transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
<template lang="html">
|
||||
<tree-detail-layout>
|
||||
<div
|
||||
slot="tree"
|
||||
class="layout column"
|
||||
style="
|
||||
background-color: inherit;
|
||||
width: initial;
|
||||
max-width: 100%;
|
||||
min-width: 320px;
|
||||
height: 100%;
|
||||
"
|
||||
>
|
||||
<v-toolbar
|
||||
flat
|
||||
:color="selectedNode && selectedNode.color || 'secondary'"
|
||||
:dark="isToolbarDark"
|
||||
:light="!isToolbarDark"
|
||||
>
|
||||
<v-spacer />
|
||||
<v-switch
|
||||
v-model="organize"
|
||||
label="Organize"
|
||||
class="mx-3"
|
||||
style="flex-grow: 0; height: 32px;"
|
||||
/>
|
||||
</v-toolbar>
|
||||
<library-contents-container
|
||||
:library-id="library._id"
|
||||
:organize-mode="organize"
|
||||
:edit-mode="editMode"
|
||||
:selected-node-id="selected"
|
||||
should-subscribe
|
||||
style="overflow-y: auto;"
|
||||
@selected="clickNode"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
slot="detail"
|
||||
data-id="selected-node-card"
|
||||
style="overflow: hidden;"
|
||||
>
|
||||
<library-node-dialog
|
||||
:_id="selected"
|
||||
embedded
|
||||
@removed="selected = undefined"
|
||||
/>
|
||||
</div>
|
||||
</tree-detail-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TreeDetailLayout from '/imports/ui/components/TreeDetailLayout.vue';
|
||||
import LibraryNodeDialog from '/imports/ui/library/LibraryNodeDialog.vue';
|
||||
import LibraryNodes from '/imports/api/library/LibraryNodes.js';
|
||||
import Libraries from '/imports/api/library/Libraries.js';
|
||||
import { getPropertyName } from '/imports/constants/PROPERTIES.js';
|
||||
import isDarkColor from '/imports/ui/utility/isDarkColor.js';
|
||||
import LibraryContentsContainer from '/imports/ui/library/LibraryContentsContainer.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TreeDetailLayout,
|
||||
LibraryContentsContainer,
|
||||
LibraryNodeDialog,
|
||||
},
|
||||
props: {
|
||||
selection: Boolean,
|
||||
},
|
||||
data(){ return {
|
||||
organize: false,
|
||||
selected: undefined,
|
||||
};},
|
||||
computed: {
|
||||
isToolbarDark(){
|
||||
return isDarkColor(
|
||||
this.selectedNode && this.selectedNode.color ||
|
||||
this.$vuetify.theme.secondary
|
||||
);
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
selectedNode(val){
|
||||
this.$emit('selected', val)
|
||||
},
|
||||
'library.name'(value){
|
||||
this.$store.commit('setPageTitle', value || 'Library');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
editLibraryNode(){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'library-node-edit-dialog',
|
||||
elementId: 'selected-node-card',
|
||||
data: {_id: this.selected},
|
||||
});
|
||||
},
|
||||
clickNode(id){
|
||||
if (this.$vuetify.breakpoint.mdAndUp){
|
||||
this.selected = id;
|
||||
} else {
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'library-node-dialog',
|
||||
elementId: `tree-node-${id}`,
|
||||
data: {
|
||||
_id: id,
|
||||
selection: this.selection,
|
||||
},
|
||||
callback: result => {
|
||||
if (result){
|
||||
this.selected = id;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
getPropertyName,
|
||||
},
|
||||
meteor: {
|
||||
library(){
|
||||
return Libraries.findOne(this.$route.params.id);
|
||||
},
|
||||
selectedNode(){
|
||||
return LibraryNodes.findOne({
|
||||
_id: this.selected,
|
||||
removed: {$ne: true}
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -1,28 +1,53 @@
|
||||
<template lang="html">
|
||||
<v-toolbar-items>
|
||||
<v-btn
|
||||
v-if="showSubscribeButton"
|
||||
flat
|
||||
:loading="loading"
|
||||
@click="subscribe(!subscribed)"
|
||||
>
|
||||
{{ subscribed ? 'Unsubscribe' : 'Subscribe' }}
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="canEdit"
|
||||
flat
|
||||
icon
|
||||
data-id="library-edit-button"
|
||||
@click="editLibrary(library._id)"
|
||||
>
|
||||
<v-icon>create</v-icon>
|
||||
</v-btn>
|
||||
</v-toolbar-items>
|
||||
<v-toolbar
|
||||
app
|
||||
color="secondary"
|
||||
dark
|
||||
tabs
|
||||
extended
|
||||
dense
|
||||
>
|
||||
<v-toolbar-side-icon @click="toggleDrawer" />
|
||||
<v-toolbar-items>
|
||||
<v-btn
|
||||
flat
|
||||
icon
|
||||
@click="$router.push('/library')"
|
||||
>
|
||||
<v-icon>arrow_back</v-icon>
|
||||
</v-btn>
|
||||
</v-toolbar-items>
|
||||
<v-toolbar-title>
|
||||
{{ library && library.name }}
|
||||
</v-toolbar-title>
|
||||
<v-spacer />
|
||||
<v-toolbar-items>
|
||||
<v-btn
|
||||
v-if="showSubscribeButton"
|
||||
flat
|
||||
:loading="loading"
|
||||
@click="subscribe(!subscribed)"
|
||||
>
|
||||
{{ subscribed ? 'Unsubscribe' : 'Subscribe' }}
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="canEdit"
|
||||
flat
|
||||
icon
|
||||
data-id="library-edit-button"
|
||||
@click="editLibrary(library._id)"
|
||||
>
|
||||
<v-icon>settings</v-icon>
|
||||
</v-btn>
|
||||
</v-toolbar-items>
|
||||
</v-toolbar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Libraries from '/imports/api/library/Libraries.js';
|
||||
import { assertDocEditPermission } from '/imports/api/sharing/sharingPermissions.js';
|
||||
import { mapMutations } from 'vuex';
|
||||
|
||||
export default {
|
||||
data(){ return {
|
||||
loading: false,
|
||||
@@ -33,8 +58,10 @@ export default {
|
||||
},
|
||||
subscribed(){
|
||||
let libraryId = this.$route.params.id;
|
||||
let subs = Meteor.user().subscribedLibraries;
|
||||
return subs.includes(libraryId);
|
||||
let user = Meteor.user();
|
||||
if (!user) return false;
|
||||
let subs = user.subscribedLibraries;
|
||||
return subs && subs.includes(libraryId);
|
||||
},
|
||||
showSubscribeButton(){
|
||||
let userId = Meteor.userId();
|
||||
@@ -60,6 +87,9 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations([
|
||||
'toggleDrawer',
|
||||
]),
|
||||
subscribe(value){
|
||||
this.loading = true;
|
||||
Meteor.users.subscribeToLibrary.call({
|
||||
@@ -1,14 +0,0 @@
|
||||
<template lang="html">
|
||||
<single-card-layout>
|
||||
<single-library />
|
||||
</single-card-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SingleLibrary from '/imports/ui/library/SingleLibrary.vue';
|
||||
export default {
|
||||
components: {
|
||||
SingleLibrary,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -6,8 +6,7 @@ import Home from '/imports/ui/pages/Home.vue';
|
||||
import About from '/imports/ui/pages/About.vue';
|
||||
import CharacterList from '/imports/ui/pages/CharacterList.vue';
|
||||
import Library from '/imports/ui/pages/Library.vue';
|
||||
import SingleLibraryPage from '/imports/ui/pages/SingleLibraryPage.vue'
|
||||
import SingleLibraryToolbarItems from '/imports/ui/library/SingleLibraryToolbarItems.vue'
|
||||
import SingleLibraryToolbar from '/imports/ui/library/SingleLibraryToolbar.vue';
|
||||
import CharacterSheetPage from '/imports/ui/pages/CharacterSheetPage.vue';
|
||||
import CharacterSheetToolbar from '/imports/ui/creature/character/CharacterSheetToolbar.vue';
|
||||
import CharacterSheetRightDrawer from '/imports/ui/creature/character/CharacterSheetRightDrawer.vue';
|
||||
@@ -123,8 +122,8 @@ RouterFactory.configure(factory => {
|
||||
name: 'singleLibrary',
|
||||
path: '/library/:id',
|
||||
components: {
|
||||
default: SingleLibraryPage,
|
||||
toolbarItems: SingleLibraryToolbarItems,
|
||||
default: Library,
|
||||
toolbar: SingleLibraryToolbar,
|
||||
},
|
||||
meta: {
|
||||
title: 'Library',
|
||||
|
||||
Reference in New Issue
Block a user