Compare commits
3 Commits
2.0-beta.7
...
2.0-beta.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21b823f85c | ||
|
|
4631579181 | ||
|
|
edf3920e84 |
@@ -143,7 +143,15 @@ const updateCreature = new ValidatedMethod({
|
|||||||
validate({_id, path}){
|
validate({_id, path}){
|
||||||
if (!_id) return false;
|
if (!_id) return false;
|
||||||
// Allowed fields
|
// Allowed fields
|
||||||
let allowedFields = ['name', 'alignment', 'gender', 'picture', 'avatarPicture', 'settings'];
|
let allowedFields = [
|
||||||
|
'name',
|
||||||
|
'alignment',
|
||||||
|
'gender',
|
||||||
|
'picture',
|
||||||
|
'avatarPicture',
|
||||||
|
'color',
|
||||||
|
'settings',
|
||||||
|
];
|
||||||
if (!allowedFields.includes(path[0])){
|
if (!allowedFields.includes(path[0])){
|
||||||
throw new Meteor.Error('Creatures.methods.update.denied',
|
throw new Meteor.Error('Creatures.methods.update.denied',
|
||||||
'This field can\'t be updated using this method');
|
'This field can\'t be updated using this method');
|
||||||
@@ -152,9 +160,15 @@ const updateCreature = new ValidatedMethod({
|
|||||||
run({_id, path, value}) {
|
run({_id, path, value}) {
|
||||||
let creature = Creatures.findOne(_id);
|
let creature = Creatures.findOne(_id);
|
||||||
assertEditPermission(creature, this.userId);
|
assertEditPermission(creature, this.userId);
|
||||||
Creatures.update(_id, {
|
if (value === undefined || value === null){
|
||||||
$set: {[path.join('.')]: value},
|
Creatures.update(_id, {
|
||||||
});
|
$unset: {[path.join('.')]: 1},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Creatures.update(_id, {
|
||||||
|
$set: {[path.join('.')]: value},
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
<template lang="html">
|
<template lang="html">
|
||||||
<dialog-base>
|
<dialog-base :color="model.color">
|
||||||
<v-toolbar-title slot="toolbar">
|
<template slot="toolbar">
|
||||||
Creature Form Dialog
|
<v-toolbar-title>
|
||||||
</v-toolbar-title>
|
Creature Form Dialog
|
||||||
|
</v-toolbar-title>
|
||||||
|
<v-spacer />
|
||||||
|
<color-picker
|
||||||
|
:value="model.color"
|
||||||
|
@input="value => change({path: ['color'], value})"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
<div>
|
<div>
|
||||||
<creature-form
|
<creature-form
|
||||||
:model="model"
|
:model="model"
|
||||||
@@ -27,11 +34,13 @@ import {updateCreature} from '/imports/api/creature/Creatures.js';
|
|||||||
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
|
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
|
||||||
import CreatureForm from '/imports/ui/creature/CreatureForm.vue'
|
import CreatureForm from '/imports/ui/creature/CreatureForm.vue'
|
||||||
import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js';
|
import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js';
|
||||||
|
import ColorPicker from '/imports/ui/components/ColorPicker.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
DialogBase,
|
DialogBase,
|
||||||
CreatureForm,
|
CreatureForm,
|
||||||
|
ColorPicker,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
_id: String,
|
_id: String,
|
||||||
@@ -52,8 +61,16 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
change({path, value, ack}){
|
change({path, value, ack}){
|
||||||
updateCreature.call({_id: this._id, path, value}, (error, result) =>{
|
updateCreature.call({_id: this._id, path, value}, (error) =>{
|
||||||
ack && ack(error && error.reason || error);
|
if (error){
|
||||||
|
if(ack){
|
||||||
|
ack(error && error.reason || error)
|
||||||
|
} else {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
} else if (ack) {
|
||||||
|
ack();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
247
app/imports/ui/creature/character/CharacterSheetToolbar.vue
Normal file
247
app/imports/ui/creature/character/CharacterSheetToolbar.vue
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
<template lang="html">
|
||||||
|
<v-toolbar
|
||||||
|
app
|
||||||
|
class="character-sheet-toolbar"
|
||||||
|
:color="toolbarColor"
|
||||||
|
:dark="isDark"
|
||||||
|
:light="!isDark"
|
||||||
|
tabs
|
||||||
|
dense
|
||||||
|
>
|
||||||
|
<v-toolbar-side-icon @click="toggleDrawer" />
|
||||||
|
<v-toolbar-title>
|
||||||
|
<v-fade-transition
|
||||||
|
mode="out-in"
|
||||||
|
>
|
||||||
|
<div :key="$store.state.pageTitle">
|
||||||
|
{{ $store.state.pageTitle }}
|
||||||
|
</div>
|
||||||
|
</v-fade-transition>
|
||||||
|
</v-toolbar-title>
|
||||||
|
<v-spacer />
|
||||||
|
<v-fade-transition
|
||||||
|
mode="out-in"
|
||||||
|
>
|
||||||
|
<div :key="$route.meta.title">
|
||||||
|
<v-toolbar-items v-if="creature">
|
||||||
|
<v-btn
|
||||||
|
v-if="editPermission"
|
||||||
|
flat
|
||||||
|
icon
|
||||||
|
@click="recompute(creature._id)"
|
||||||
|
>
|
||||||
|
<v-icon>refresh</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-menu
|
||||||
|
bottom
|
||||||
|
left
|
||||||
|
transition="slide-y-transition"
|
||||||
|
data-id="creature-menu"
|
||||||
|
>
|
||||||
|
<template #activator="{ on }">
|
||||||
|
<v-btn
|
||||||
|
icon
|
||||||
|
v-on="on"
|
||||||
|
>
|
||||||
|
<v-icon>more_vert</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
<v-list v-if="editPermission">
|
||||||
|
<v-list-tile @click="deleteCharacter">
|
||||||
|
<v-list-tile-title>
|
||||||
|
<v-icon>delete</v-icon> Delete
|
||||||
|
</v-list-tile-title>
|
||||||
|
</v-list-tile>
|
||||||
|
<v-list-tile @click="showCharacterForm">
|
||||||
|
<v-list-tile-title>
|
||||||
|
<v-icon>create</v-icon> Edit details
|
||||||
|
</v-list-tile-title>
|
||||||
|
</v-list-tile>
|
||||||
|
<v-list-tile @click="showShareDialog">
|
||||||
|
<v-list-tile-title>
|
||||||
|
<v-icon>share</v-icon> Sharing
|
||||||
|
</v-list-tile-title>
|
||||||
|
</v-list-tile>
|
||||||
|
</v-list>
|
||||||
|
<v-list v-else>
|
||||||
|
<v-list-tile @click="unshareWithMe">
|
||||||
|
<v-list-tile-title>
|
||||||
|
<v-icon>delete</v-icon> Unshare with me
|
||||||
|
</v-list-tile-title>
|
||||||
|
</v-list-tile>
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
|
</v-toolbar-items>
|
||||||
|
</div>
|
||||||
|
</v-fade-transition>
|
||||||
|
<v-fade-transition
|
||||||
|
slot="extension"
|
||||||
|
mode="out-in"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
:key="$route.meta.title"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<v-tabs
|
||||||
|
v-if="creature"
|
||||||
|
slot="extension"
|
||||||
|
:value="value"
|
||||||
|
centered
|
||||||
|
grow
|
||||||
|
max="100px"
|
||||||
|
@change="e => $emit('input', e)"
|
||||||
|
>
|
||||||
|
<v-tab>
|
||||||
|
Stats
|
||||||
|
</v-tab>
|
||||||
|
<v-tab>
|
||||||
|
Features
|
||||||
|
</v-tab>
|
||||||
|
<v-tab>
|
||||||
|
Inventory
|
||||||
|
</v-tab>
|
||||||
|
<v-tab>
|
||||||
|
Spells
|
||||||
|
</v-tab>
|
||||||
|
<v-tab>
|
||||||
|
Persona
|
||||||
|
</v-tab>
|
||||||
|
<v-tab>
|
||||||
|
Tree
|
||||||
|
</v-tab>
|
||||||
|
</v-tabs>
|
||||||
|
</div>
|
||||||
|
</v-fade-transition>
|
||||||
|
</v-toolbar>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Creatures from '/imports/api/creature/Creatures.js';
|
||||||
|
import removeCreature from '/imports/api/creature/removeCreature.js';
|
||||||
|
import { mapMutations } from 'vuex';
|
||||||
|
import { theme } from '/imports/ui/theme.js';
|
||||||
|
import { recomputeCreature } from '/imports/api/creature/computation/recomputeCreature.js';
|
||||||
|
import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js';
|
||||||
|
import { updateUserSharePermissions } from '/imports/api/sharing/sharing.js';
|
||||||
|
import isDarkColor from '/imports/ui/utility/isDarkColor.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data(){return {
|
||||||
|
theme,
|
||||||
|
}},
|
||||||
|
computed: {
|
||||||
|
creatureId(){
|
||||||
|
return this.$route.params.id;
|
||||||
|
},
|
||||||
|
toolbarColor(){
|
||||||
|
if (this.creature && this.creature.color){
|
||||||
|
return this.creature.color;
|
||||||
|
} else {
|
||||||
|
return this.$vuetify.theme.secondary;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isDark(){
|
||||||
|
return isDarkColor(this.toolbarColor);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapMutations([
|
||||||
|
'toggleDrawer',
|
||||||
|
]),
|
||||||
|
recompute(charId){
|
||||||
|
recomputeCreature.call({charId});
|
||||||
|
},
|
||||||
|
showCharacterForm(){
|
||||||
|
this.$store.commit('pushDialogStack', {
|
||||||
|
component: 'creature-form-dialog',
|
||||||
|
elementId: 'creature-menu',
|
||||||
|
data: {
|
||||||
|
_id: this.creatureId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
showShareDialog(){
|
||||||
|
this.$store.commit('pushDialogStack', {
|
||||||
|
component: 'share-dialog',
|
||||||
|
elementId: 'creature-menu',
|
||||||
|
data: {
|
||||||
|
docRef: {
|
||||||
|
id: this.creatureId,
|
||||||
|
collection: 'creatures',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteCharacter(){
|
||||||
|
let that = this;
|
||||||
|
this.$store.commit('pushDialogStack', {
|
||||||
|
component: 'delete-confirmation-dialog',
|
||||||
|
elementId: 'creature-menu',
|
||||||
|
data: {
|
||||||
|
name: this.creature.name,
|
||||||
|
typeName: 'Character'
|
||||||
|
},
|
||||||
|
callback(confirmation){
|
||||||
|
if(!confirmation) return;
|
||||||
|
removeCreature.call({charId: that.creatureId}, (error) => {
|
||||||
|
if (error) {
|
||||||
|
console.error(error);
|
||||||
|
} else {
|
||||||
|
that.$router.push('/characterList');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
unshareWithMe(){
|
||||||
|
updateUserSharePermissions.call({
|
||||||
|
docRef: {
|
||||||
|
collection: 'creatures',
|
||||||
|
id: this.creatureId,
|
||||||
|
},
|
||||||
|
userId: Meteor.userId(),
|
||||||
|
role: 'none',
|
||||||
|
}, (error) => {
|
||||||
|
if (error) {
|
||||||
|
console.error(error);
|
||||||
|
} else {
|
||||||
|
this.$router.push('/characterList');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
meteor: {
|
||||||
|
$subscribe: {
|
||||||
|
'singleCharacter'(){
|
||||||
|
return [this.creatureId];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
creature(){
|
||||||
|
return Creatures.findOne(this.creatureId);
|
||||||
|
},
|
||||||
|
editPermission(){
|
||||||
|
try {
|
||||||
|
assertEditPermission(this.creature, Meteor.userId());
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="css">
|
||||||
|
.character-sheet-toolbar .v-tabs__container--grow .v-tabs__div {
|
||||||
|
max-width: 120px !important;
|
||||||
|
}
|
||||||
|
.character-sheet-toolbar .v-tabs__bar {
|
||||||
|
background: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="inventory">
|
<div class="inventory">
|
||||||
<column-layout>
|
<column-layout>
|
||||||
<div>
|
<div>
|
||||||
<toolbar-card color="">
|
<toolbar-card :color="$vuetify.theme.secondary">
|
||||||
<v-spacer slot="toolbar" />
|
<v-spacer slot="toolbar" />
|
||||||
<v-switch
|
<v-switch
|
||||||
v-if="context.editPermission !== false"
|
v-if="context.editPermission !== false"
|
||||||
|
|||||||
@@ -4,14 +4,17 @@
|
|||||||
:light="!darkMode"
|
:light="!darkMode"
|
||||||
>
|
>
|
||||||
<v-navigation-drawer
|
<v-navigation-drawer
|
||||||
v-if="$route.path !== '/countdown'"
|
|
||||||
v-model="drawer"
|
v-model="drawer"
|
||||||
app
|
app
|
||||||
>
|
>
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
</v-navigation-drawer>
|
</v-navigation-drawer>
|
||||||
|
<router-view
|
||||||
|
v-model="tabs"
|
||||||
|
name="toolbar"
|
||||||
|
/>
|
||||||
<v-toolbar
|
<v-toolbar
|
||||||
v-if="$route.path !== '/countdown'"
|
v-if="!$route.matched[0].components.toolbar"
|
||||||
app
|
app
|
||||||
color="secondary"
|
color="secondary"
|
||||||
dark
|
dark
|
||||||
@@ -116,6 +119,9 @@
|
|||||||
'toggleDrawer',
|
'toggleDrawer',
|
||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
|
mounted(){
|
||||||
|
console.log(this.$route);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
<v-alert
|
<v-alert
|
||||||
v-if="$route.path !== '/countdown'"
|
|
||||||
icon="priority_high"
|
icon="priority_high"
|
||||||
type="error"
|
type="error"
|
||||||
dismissible
|
dismissible
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { RouterFactory, nativeScrollBehavior } from 'meteor/akryum:vue-router2';
|
import { RouterFactory, nativeScrollBehavior } from 'meteor/akryum:vue-router2';
|
||||||
import LAUNCH_DATE from '/imports/constants/LAUNCH_DATE.js';
|
|
||||||
import { acceptInviteToken } from '/imports/api/users/Invites.js';
|
import { acceptInviteToken } from '/imports/api/users/Invites.js';
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
@@ -10,8 +9,7 @@ import Library from '/imports/ui/pages/Library.vue';
|
|||||||
import SingleLibraryPage from '/imports/ui/pages/SingleLibraryPage.vue'
|
import SingleLibraryPage from '/imports/ui/pages/SingleLibraryPage.vue'
|
||||||
import SingleLibraryToolbarItems from '/imports/ui/library/SingleLibraryToolbarItems.vue'
|
import SingleLibraryToolbarItems from '/imports/ui/library/SingleLibraryToolbarItems.vue'
|
||||||
import CharacterSheetPage from '/imports/ui/pages/CharacterSheetPage.vue';
|
import CharacterSheetPage from '/imports/ui/pages/CharacterSheetPage.vue';
|
||||||
import CharacterSheetToolbarItems from '/imports/ui/creature/character/CharacterSheetToolbarItems.vue';
|
import CharacterSheetToolbar from '/imports/ui/creature/character/CharacterSheetToolbar.vue';
|
||||||
import CharacterSheetToolbarExtension from '/imports/ui/creature/character/CharacterSheetToolbarExtension.vue';
|
|
||||||
import SignIn from '/imports/ui/pages/SignIn.vue' ;
|
import SignIn from '/imports/ui/pages/SignIn.vue' ;
|
||||||
import Register from '/imports/ui/pages/Register.vue';
|
import Register from '/imports/ui/pages/Register.vue';
|
||||||
import IconAdmin from '/imports/ui/icons/IconAdmin.vue';
|
import IconAdmin from '/imports/ui/icons/IconAdmin.vue';
|
||||||
@@ -22,7 +20,6 @@ import InviteSuccess from '/imports/ui/pages/InviteSuccess.vue' ;
|
|||||||
import InviteError from '/imports/ui/pages/InviteError.vue' ;
|
import InviteError from '/imports/ui/pages/InviteError.vue' ;
|
||||||
import NotImplemented from '/imports/ui/pages/NotImplemented.vue';
|
import NotImplemented from '/imports/ui/pages/NotImplemented.vue';
|
||||||
import PatreonLevelTooLow from '/imports/ui/pages/PatreonLevelTooLow.vue';
|
import PatreonLevelTooLow from '/imports/ui/pages/PatreonLevelTooLow.vue';
|
||||||
import LaunchCountdown from '/imports/ui/pages/LaunchCountdown.vue';
|
|
||||||
|
|
||||||
let userSubscription = Meteor.subscribe('user');
|
let userSubscription = Meteor.subscribe('user');
|
||||||
|
|
||||||
@@ -91,17 +88,7 @@ function claimInvite(to, from, next){
|
|||||||
}
|
}
|
||||||
|
|
||||||
RouterFactory.configure(factory => {
|
RouterFactory.configure(factory => {
|
||||||
factory.addRoutes([
|
factory.addRoutes([{
|
||||||
{
|
|
||||||
path: '/countdown',
|
|
||||||
name: 'Countdown',
|
|
||||||
components: {
|
|
||||||
default: LaunchCountdown,
|
|
||||||
},
|
|
||||||
meta: {
|
|
||||||
title: 'Countdown to Launch',
|
|
||||||
},
|
|
||||||
},{
|
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'home',
|
name: 'home',
|
||||||
components: {
|
components: {
|
||||||
@@ -142,8 +129,7 @@ RouterFactory.configure(factory => {
|
|||||||
path: '/character/:id/:urlName',
|
path: '/character/:id/:urlName',
|
||||||
components: {
|
components: {
|
||||||
default: CharacterSheetPage,
|
default: CharacterSheetPage,
|
||||||
toolbarExtension: CharacterSheetToolbarExtension,
|
toolbar: CharacterSheetToolbar,
|
||||||
toolbarItems: CharacterSheetToolbarItems,
|
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
title: 'Character Sheet',
|
title: 'Character Sheet',
|
||||||
@@ -152,8 +138,7 @@ RouterFactory.configure(factory => {
|
|||||||
path: '/character/:id',
|
path: '/character/:id',
|
||||||
components: {
|
components: {
|
||||||
default: CharacterSheetPage,
|
default: CharacterSheetPage,
|
||||||
toolbarExtension: CharacterSheetToolbarExtension,
|
toolbar: CharacterSheetToolbar,
|
||||||
toolbarItems: CharacterSheetToolbarItems,
|
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
title: 'Character Sheet',
|
title: 'Character Sheet',
|
||||||
@@ -263,13 +248,10 @@ const router = routerFactory.create();
|
|||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
let user = Meteor.user();
|
let user = Meteor.user();
|
||||||
if (
|
if (
|
||||||
to.path === '/countdown' ||
|
|
||||||
to.path === '/sign-in' ||
|
to.path === '/sign-in' ||
|
||||||
(user && user.roles && user.roles.includes('admin'))
|
(user && user.roles && user.roles.includes('admin'))
|
||||||
){
|
){
|
||||||
next();
|
next();
|
||||||
} else if (new Date() < LAUNCH_DATE){
|
|
||||||
next('/countdown');
|
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const theme = {
|
|||||||
|
|
||||||
const darkTheme = {
|
const darkTheme = {
|
||||||
primary: '#f44336',
|
primary: '#f44336',
|
||||||
secondary: '#757575',
|
secondary: '#212121',
|
||||||
accent: '#f44336',
|
accent: '#f44336',
|
||||||
error: '#FF6D00',
|
error: '#FF6D00',
|
||||||
warning: '#FFB300',
|
warning: '#FFB300',
|
||||||
|
|||||||
Reference in New Issue
Block a user