Greatly improved look and feel of site navigation

This commit is contained in:
Thaum Rystra
2020-05-02 17:09:56 +02:00
parent 073578b90d
commit d649fb9d54
26 changed files with 1035 additions and 831 deletions

View File

@@ -140,3 +140,13 @@ Meteor.users.findUserByUsernameOrEmail = new ValidatedMethod({
return user && user._id;
}
});
export function getEntitledCentsOfUser(user){
if (!user) return 0;
const patreon = user.services && user.services.patreon;
if (!patreon) return 0;
let entitledCents = patreon.entitledCents || 0;
let overrideCents = patreon.entitledCentsOverride || 0;
if (overrideCents > entitledCents) entitledCents = overrideCents;
return entitledCents;
}

View File

@@ -1,6 +1,9 @@
<template lang="html" functional>
<template
lang="html"
functional
>
<div class="column-layout">
<slot/>
<slot />
</div>
</template>
@@ -11,7 +14,7 @@ export default {
<style lang="css" scoped>
.column-layout {
column-count: 4;
column-count: 12;
column-fill: balance;
column-gap: 0;
column-width: 240px;

View File

@@ -1,33 +1,34 @@
<template lang="html">
<div class="creature-form">
<text-field
label="Name"
:value="model.name"
@change="(value, ack) => $emit('change', {path: ['name'], value, ack})"
:error-messages="errors.name"
:debounce-time="debounceTime"
/>
<text-field
label="Alignment"
:value="model.alignment"
@change="(value, ack) => $emit('change', {path: ['alignment'], value, ack})"
:error-messages="errors.alignment"
:debounce-time="debounceTime"
/>
<text-field
label="Gender"
:value="model.gender"
@change="(value, ack) => $emit('change', {path: ['gender'], value, ack})"
:error-messages="errors.gender"
:debounce-time="debounceTime"
/>
<text-field
label="Picture URL"
:value="model.picture"
@change="(value, ack) => $emit('change', {path: ['picture'], value, ack})"
:error-messages="errors.picture"
:debounce-time="debounceTime"
/>
<div class="creature-form">
<text-field
label="Name"
:value="model.name"
:error-messages="errors.name"
:debounce-time="debounceTime"
@change="(value, ack) => $emit('change', {path: ['name'], value, ack})"
/>
<text-field
label="Alignment"
:value="model.alignment"
:error-messages="errors.alignment"
:debounce-time="debounceTime"
@change="(value, ack) => $emit('change', {path: ['alignment'], value, ack})"
/>
<text-field
label="Gender"
:value="model.gender"
:error-messages="errors.gender"
:debounce-time="debounceTime"
@change="(value, ack) => $emit('change', {path: ['gender'], value, ack})"
/>
<text-field
label="Picture URL"
:value="model.picture"
:error-messages="errors.picture"
:debounce-time="debounceTime"
@change="(value, ack) => $emit('change', {path: ['picture'], value, ack})"
/>
<!--
<form-sections>
<form-section name="settings">
<v-switch
@@ -50,7 +51,8 @@
/>
</form-section>
</form-sections>
</div>
-->
</div>
</template>
<script>

View File

@@ -1,115 +1,46 @@
<template>
<div class="character-sheet layout column">
<v-toolbar
app
clipped-left
:color="creature.color || 'secondary'"
:dark="isDarkColor(creature.color || theme.primary)"
>
<v-btn
v-if="showMenuButton"
flat
icon
@click="toggleDrawer"
<div class="character-sheet fill-height">
<v-fade-transition mode="out-in">
<div
v-if="$subReady.singleCharacter"
key="character-tabs"
class="fill-height"
>
<v-icon>menu</v-icon>
</v-btn>
<div class="flex">
{{ creature.name }}
<v-tabs-items
v-model="tabs"
>
<v-tab-item>
<stats-tab :creature-id="creatureId" />
</v-tab-item>
<v-tab-item>
<features-tab :creature-id="creatureId" />
</v-tab-item>
<v-tab-item>
<inventory-tab :creature-id="creatureId" />
</v-tab-item>
<v-tab-item>
<spells-tab :creature-id="creatureId" />
</v-tab-item>
<v-tab-item>
<persona-tab :creature-id="creatureId" />
</v-tab-item>
<v-tab-item>
<tree-tab :creature-id="creatureId" />
</v-tab-item>
</v-tabs-items>
</div>
<v-btn
flat
icon
@click="recompute(creature._id)"
<div
v-else
key="character-loading"
class="fill-height layout justify-center align-center"
>
<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-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-menu>
<v-tabs
slot="extension"
v-model="tab"
centered
grow
>
<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>
</v-toolbar>
<v-content
v-if="$subReady.singleCharacter"
class="flex"
>
<v-tabs-items v-model="tab">
<v-tab-item>
<stats-tab :creature-id="creatureId" />
</v-tab-item>
<v-tab-item>
<features-tab :creature-id="creatureId" />
</v-tab-item>
<v-tab-item>
<inventory-tab :creature-id="creatureId" />
</v-tab-item>
<v-tab-item>
<spells-tab :creature-id="creatureId" />
</v-tab-item>
<v-tab-item>
<persona-tab :creature-id="creatureId" />
</v-tab-item>
<v-tab-item>
<tree-tab :creature-id="creatureId" />
</v-tab-item>
</v-tabs-items>
</v-content>
<v-content v-else>
<v-progress-circular indeterminate />
</v-content>
<v-progress-circular
indeterminate
color="primary"
size="64"
/>
</div>
</v-fade-transition>
</div>
</template>
@@ -139,70 +70,26 @@
TreeTab,
},
props: {
showMenuButton: Boolean,
creatureId: {
type: String,
required: true,
},
tabs: {
type: Number,
required: true,
},
},
reactiveProvide: {
name: 'computationContext',
include: ['creature'],
},
data(){return {
theme,
tab: 0,
}},
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');
}
});
}
});
},
isDarkColor,
onMounted(){
this.$store.commit('setPageTitle', this.creature && this.creature.name || 'Character Sheet');
},
watch: {
'creature.name'(value){
this.$store.commit('setPageTitle', value || 'Character Sheet');
},
},
meteor: {
$subscribe: {
@@ -216,18 +103,3 @@
},
}
</script>
<style>
.v-tabs__bar {
background: none !important;
}
.v-tabs__container--grow .v-tabs__div {
max-width: 180px !important;
}
.v-window-item, .v-window, .v-window__container {
height: 100%;
}
.v-window-item {
padding: 0.1px;
}
</style>

View File

@@ -0,0 +1,46 @@
<template lang="html">
<v-tabs
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>
</template>
<script>
export default {
props: {
value: {
type: Number,
required: true,
},
}
}
</script>
<style lang="css" scoped>
.v-tabs__container--grow .v-tabs__div {
max-width: 120px !important;
}
</style>

View File

@@ -0,0 +1,127 @@
<template lang="html">
<v-toolbar-items>
<v-btn
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-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-menu>
</v-toolbar-items>
</template>
<script>
import Creatures from '/imports/api/creature/Creatures.js';
import removeCreature from '/imports/api/creature/removeCreature.js';
import isDarkColor from '/imports/ui/utility/isDarkColor.js';
import { mapMutations } from 'vuex';
import { theme } from '/imports/ui/theme.js';
import { recomputeCreature } from '/imports/api/creature/computation/recomputeCreature.js';
export default {
data(){return {
theme,
}},
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');
}
});
}
});
},
isDarkColor,
},
computed: {
creatureId(){
return this.$route.params.id;
},
},
meteor: {
$subscribe: {
'singleCharacter'(){
return [this.creatureId];
},
},
creature(){
return Creatures.findOne(this.creatureId) || {};
},
},
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,83 +1,96 @@
<template lang="html">
<toolbar-layout>
<div slot="toolbar">
DiceCloud
</div>
<div>
<div class="content">
<v-card class="ma-4">
<v-card-text>
<v-layout column align-center>
<upload-btn
:fileChangedCallback="fileChanged"
/>
<v-text-field
label="Search"
@click:append="updateSearchString"
@keydown.enter="updateSearchString"
ref="iconSearchField"
append-icon="search"
/>
<v-container grid-list-md fill-height>
<v-layout row wrap>
<v-flex xs3 md2 xl1 v-for="icon in icons" :key="icon._id._str || icon._id">
<v-card>
<v-card-title class="title">{{icon.name}}</v-card-title>
<v-card-text>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#000" :d="icon.shape"/></svg>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-layout>
</v-card-text>
</v-card>
</div>
</toolbar-layout>
<v-card class="ma-4">
<v-card-text>
<v-layout
column
align-center
>
<upload-btn
:file-changed-callback="fileChanged"
/>
<v-text-field
ref="iconSearchField"
label="Search"
append-icon="search"
@click:append="updateSearchString"
@keydown.enter="updateSearchString"
/>
<v-container
grid-list-md
fill-height
>
<v-layout
row
wrap
>
<v-flex
v-for="icon in icons"
:key="icon._id._str || icon._id"
xs3
md2
xl1
>
<v-card>
<v-card-title class="title">
{{ icon.name }}
</v-card-title>
<v-card-text>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
><path
fill="#000"
:d="icon.shape"
/></svg>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-layout>
</v-card-text>
</v-card>
</div>
</div>
</template>
<script>
import UploadButton from 'vuetify-upload-button';
import ToolbarLayout from "/imports/ui/layouts/ToolbarLayout.vue";
import importIcons from '/imports/ui/icons/importIcons.js';
import Icons from '/imports/api/icons/Icons.js';
import { _ } from 'meteor/underscore';
import importIcons from '/imports/ui/icons/importIcons.js';
import Icons from '/imports/api/icons/Icons.js';
export default {
data(){ return {
searchString: '',
}},
methods: {
export default {
data(){ return {
searchString: '',
}},
methods: {
fileChanged (file) {
importIcons(file);
importIcons(file);
},
updateSearchString(){
this.searchString = this.$refs.iconSearchField.internalValue;
},
updateSearchString(){
this.searchString = this.$refs.iconSearchField.internalValue;
},
},
components: {
ToolbarLayout,
'upload-btn': UploadButton
meteor: {
$subscribe: {
searchIcons() {
return [this.searchString];
},
},
icons(){
return Icons.find({}, { sort: [['score', 'desc']] });
},
},
meteor: {
$subscribe: {
searchIcons() {
return [this.searchString];
},
},
icons(){
return Icons.find({}, { sort: [["score", "desc"]] });
},
},
};
};
</script>
<style lang="css" scoped>
svg {
height: 64px;
width: 64px;
height: 64px;
width: 64px;
}
.v-card {
height: 100%;
}
.v-card {
height: 100%;
}
</style>

View File

@@ -1,19 +1,84 @@
<template>
<v-app :dark="darkMode" :light="!darkMode">
<v-navigation-drawer app v-model="drawer" clipped>
<Sidebar/>
<v-app
:dark="darkMode"
:light="!darkMode"
>
<v-navigation-drawer
v-model="drawer"
app
>
<Sidebar />
</v-navigation-drawer>
<router-view></router-view>
<dialog-stack></dialog-stack>
<v-toolbar
app
color="secondary"
dark
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">
<router-view
name="toolbarItems"
/>
</div>
</v-fade-transition>
<v-fade-transition
slot="extension"
mode="out-in"
>
<div
:key="$route.meta.title"
style="width: 100%"
>
<router-view
v-model="tabs"
name="toolbarExtension"
/>
</div>
</v-fade-transition>
</v-toolbar>
<v-content>
<v-fade-transition
mode="out-in"
>
<router-view :tabs="tabs" />
</v-fade-transition>
</v-content>
<dialog-stack />
</v-app>
</template>
<script>
import '/imports/api/users/Users.js';
import Sidebar from "/imports/ui/layouts/Sidebar.vue";
import DialogStack from "/imports/ui/dialogStack/DialogStack.vue";
import Sidebar from '/imports/ui/layouts/Sidebar.vue';
import DialogStack from '/imports/ui/dialogStack/DialogStack.vue';
import { theme, darkTheme } from '/imports/ui/theme.js';
import { mapMutations } from 'vuex';
export default {
components: {
Sidebar,
DialogStack,
},
data(){return {
name: 'Home',
tabs: 0,
}},
computed: {
drawer: {
get () {
@@ -23,15 +88,8 @@
this.$store.commit('setDrawer', value);
},
},
},
components: {
Sidebar,
DialogStack,
},
meteor: {
$subscribe: {
'user': [],
},
darkMode(){
let user = Meteor.user();
return user && user.darkMode;
@@ -47,10 +105,17 @@
}
},
},
'$route' (to) {
this.$store.commit('setPageTitle', to.meta && to.meta.title || 'DiceCloud');
}
},
methods: {
...mapMutations([
'toggleDrawer',
]),
},
};
</script>
<style>
</style>

View File

@@ -50,7 +50,6 @@
<v-list-tile
v-for="(link, i) in links"
v-if="link.vif || link.vif === undefined"
:key="i"
:to="link.to"
:href="link.href"
@@ -98,70 +97,73 @@
</template>
<script>
import Creatures from '/imports/api/creature/Creatures.js';
import Parties from '/imports/api/campaign/Parties.js';
import Creatures from '/imports/api/creature/Creatures.js';
import Parties from '/imports/api/campaign/Parties.js';
export default {
data(){return {
showWarning: true,
}},
data(){return {
showWarning: true,
}},
meteor: {
$subscribe: {
'characterList': [],
},
signedIn(){
return Meteor.userId();
},
userName(){
let user = Meteor.user();
return user && user.username || user && user._id;
},
links(){
let links = [
{title: 'Home', icon: 'home', to: '/'},
{title: 'Characters', icon: 'group', to: '/characterList', 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'},
];
return links;
},
signedIn(){
return Meteor.userId();
},
userName(){
let user = Meteor.user();
return user && user.username || user && user._id;
},
links(){
let isLoggedIn = !!Meteor.userId();
let links = [
{title: 'Home', icon: 'home', to: '/'},
{title: 'Characters', icon: 'portrait', to: '/characterList', requireLogin: true},
{title: 'Library', icon: 'book', to: '/library', requireLogin: true},
{title: 'Friends', icon: 'people', to: '/friends', requireLogin: true},
{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'},
];
return links.filter(link => !link.requireLogin || isLoggedIn);
},
parties(){
let parties = Parties.find(
{owner: Meteor.userId()},
{sort: {name: 1}},
).map(party => {
const userId = Meteor.userId();
return Parties.find(
{owner: userId},
{sort: {name: 1}},
).map(party => {
party.characterDocs = Creatures.find(
{
_id: {$in: party.Creatures},
$or: [{readers: userId}, {writers: userId}, {owner: userId}],
}, {
{
_id: {$in: party.Creatures},
$or: [{readers: userId}, {writers: userId}, {owner: userId}],
}, {
sort: {name: 1},
fields: {name: 1, urlName: 1},
}
).map(char => {
char.url = `\/character\/${char._id}\/${char.urlName || '-'}`;
).map(char => {
char.url = `/character/${char._id}/${char.urlName || '-'}`;
return char;
});
return party;
});
},
CreaturesWithNoParty() {
var userId = Meteor.userId();
var charArrays = Parties.find({owner: userId}).map(p => p.Creatures);
var partyChars = _.uniq(_.flatten(charArrays));
return Creatures.find(
{
_id: {$nin: partyChars},
$or: [{readers: userId}, {writers: userId}, {owner: userId}],
},
{sort: {name: 1}}
).map(char => {
char.url = `\/character\/${char._id}\/${char.urlName || '-'}`;
CreaturesWithNoParty() {
var userId = Meteor.userId();
var charArrays = Parties.find({owner: userId}).map(p => p.Creatures);
var partyChars = _.uniq(_.flatten(charArrays));
return Creatures.find(
{
_id: {$nin: partyChars},
$or: [{readers: userId}, {writers: userId}, {owner: userId}],
},
{sort: {name: 1}}
).map(char => {
char.url = `/character/${char._id}/${char.urlName || '-'}`;
return char;
});
},
},
},
};
</script>

View File

@@ -1,24 +0,0 @@
<template>
<div>
<v-toolbar app color="secondary" dark clipped-left>
<v-btn flat icon @click="toggleDrawer">
<v-icon>menu</v-icon>
</v-btn>
<slot name="toolbar"></slot>
</v-toolbar>
<v-content>
<slot></slot>
</v-content>
</div>
</template>
<script>
import { mapMutations } from "vuex";
export default {
methods: {
...mapMutations([
"toggleDrawer",
]),
},
};
</script>

View File

@@ -1,54 +1,73 @@
<template lang="html">
<div class="layout row" style="background-color: inherit;">
<div
class="layout column"
style="
<div
class="layout row"
style="background-color: inherit;"
>
<div
class="layout column"
style="
background-color: inherit;
width: initial;
max-width: 100%;
min-width: 320px;
"
>
<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>
>
<v-toolbar
dense
flat
>
<v-spacer />
<v-switch
v-model="organize"
label="Organize"
class="mx-3"
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
v-if="selectedNode"
flat
icon
@click="editLibraryNode"
>
<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/shared/PropertyViewer.vue';
import LibraryNodes, { insertNode } from '/imports/api/library/LibraryNodes.js';
import LibraryNodes from '/imports/api/library/LibraryNodes.js';
import Libraries from '/imports/api/library/Libraries.js';
import PropertyIcon from '/imports/ui/properties/shared/PropertyIcon.vue';
import { getPropertyName } from '/imports/constants/PROPERTIES.js';
@@ -56,7 +75,6 @@ import { getPropertyName } from '/imports/constants/PROPERTIES.js';
export default {
components: {
LibraryBrowser,
ToolbarLayout,
PropertyViewer,
PropertyIcon,
},

View File

@@ -1,163 +1,154 @@
<template>
<toolbar-layout>
<span slot="toolbar">
Account
</span>
<v-layout
align-center
justify-center
>
<v-card class="ma-4 pa-2">
<v-list>
<v-list-tile>
<v-switch
:input-value="darkMode"
label="Dark mode"
@change="setDarkMode"
/>
</v-list-tile>
<v-subheader>
Username
</v-subheader>
<v-list-tile>
<v-list-tile-title>
{{ user && user.username }}
</v-list-tile-title>
<v-list-tile-action>
<v-tooltip left>
<span>Change Username</span>
<v-btn
slot="activator"
icon
flat
>
<v-icon>create</v-icon>
</v-btn>
</v-tooltip>
</v-list-tile-action>
</v-list-tile>
<v-subheader>
Email
</v-subheader>
<v-list-tile
v-for="email in emails"
:key="email.address"
>
<v-list-tile-title>
{{ email.address }}
</v-list-tile-title>
<v-list-tile-action>
<v-tooltip
v-if="email.verified"
left
>
<span>Verified</span>
<v-icon slot="activator">
assignment_turned_in
</v-icon>
</v-tooltip>
<v-tooltip left>
<span>Verify Account</span>
<v-btn
slot="activator"
flat
icon
@click="verifyEmail(email.address)"
>
<v-icon>assignment_late</v-icon>
</v-btn>
</v-tooltip>
</v-list-tile-action>
</v-list-tile>
<v-list-tile>
<v-list-tile-action>
<v-tooltip right>
<span>Add email address</span>
<v-btn
slot="activator"
flat
icon
>
<v-icon>add</v-icon>
</v-btn>
</v-tooltip>
</v-list-tile-action>
</v-list-tile>
<v-subheader>
API Key
</v-subheader>
<v-list-tile v-if="user && user.apiKey">
<v-list-tile v-if="showApiKey">
{{ user.apiKey }}
</v-list-tile>
<v-list-tile-title>
{{ "•".repeat(user.apiKey.length) }}
</v-list-tile-title>
<v-list-tile-action>
<div>
<v-card class="ma-4 pa-2">
<v-list>
<v-list-tile>
<v-switch
:input-value="darkMode"
label="Dark mode"
@change="setDarkMode"
/>
</v-list-tile>
<v-subheader>
Username
</v-subheader>
<v-list-tile>
<v-list-tile-title>
{{ user && user.username }}
</v-list-tile-title>
<v-list-tile-action>
<v-tooltip left>
<span>Change Username</span>
<v-btn
slot="activator"
icon
flat
>
<v-icon>create</v-icon>
</v-btn>
</v-tooltip>
</v-list-tile-action>
</v-list-tile>
<v-subheader>
Email
</v-subheader>
<v-list-tile
v-for="email in emails"
:key="email.address"
>
<v-list-tile-title>
{{ email.address }}
</v-list-tile-title>
<v-list-tile-action>
<v-tooltip
v-if="email.verified"
left
>
<span>Verified</span>
<v-icon slot="activator">
assignment_turned_in
</v-icon>
</v-tooltip>
<v-tooltip left>
<span>Verify Account</span>
<v-btn
slot="activator"
flat
icon
@click="showApiKey=!showApiKey"
@click="verifyEmail(email.address)"
>
<v-icon>{{ showApiKey ? 'visibility_off' : 'visibility' }}</v-icon>
<v-icon>assignment_late</v-icon>
</v-btn>
</v-list-tile-action>
</v-tooltip>
</v-list-tile-action>
</v-list-tile>
<v-list-tile>
<v-list-tile-action>
<v-tooltip right>
<span>Add email address</span>
<v-btn
slot="activator"
flat
icon
>
<v-icon>add</v-icon>
</v-btn>
</v-tooltip>
</v-list-tile-action>
</v-list-tile>
<v-subheader>
API Key
</v-subheader>
<v-list-tile v-if="user && user.apiKey">
<v-list-tile v-if="showApiKey">
{{ user.apiKey }}
</v-list-tile>
<v-list-tile v-else>
<v-list-tile-title>
{{ "•".repeat(user.apiKey.length) }}
</v-list-tile-title>
<v-list-tile-action>
<v-btn
flat
color="accent"
@click="generateKey"
icon
@click="showApiKey=!showApiKey"
>
Generate API Key
<v-icon>{{ showApiKey ? 'visibility_off' : 'visibility' }}</v-icon>
</v-btn>
</v-list-tile>
<!--
<v-subheader>
Google Account
</v-subheader>
<v-list-tile v-if="googleAccount">
<v-list-tile-avatar>
<img src="googleAccount.picture">
</v-list-tile-avatar>
<v-list-tile-content>
<v-list-tile-title>
{{ googleAccount.name }}
</v-list-tile-title>
<v-list-tile-sub-title>
{{ googleAccount.email }}
</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile v-else="googleAccount">
<v-btn
flat
color="accent"
>
Connect Google
</v-btn>
</v-list-tile>
-->
</v-list>
<v-card-actions>
<v-spacer />
</v-list-tile-action>
</v-list-tile>
<v-list-tile v-else>
<v-btn
flat
color="accent"
@click="signOut"
@click="generateKey"
>
Sign Out
Generate API Key
</v-btn>
</v-card-actions>
</v-card>
</v-layout>
</toolbar-layout>
</v-list-tile>
<!--
<v-subheader>
Google Account
</v-subheader>
<v-list-tile v-if="googleAccount">
<v-list-tile-avatar>
<img src="googleAccount.picture">
</v-list-tile-avatar>
<v-list-tile-content>
<v-list-tile-title>
{{ googleAccount.name }}
</v-list-tile-title>
<v-list-tile-sub-title>
{{ googleAccount.email }}
</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile v-else="googleAccount">
<v-btn
flat
color="accent"
>
Connect Google
</v-btn>
</v-list-tile>
-->
</v-list>
<v-card-actions>
<v-spacer />
<v-btn
flat
color="accent"
@click="signOut"
>
Sign Out
</v-btn>
</v-card-actions>
</v-card>
</div>
</template>
<script>
import router from '/imports/ui/router.js';
import ToolbarLayout from '/imports/ui/layouts/ToolbarLayout.vue';
export default {
meteor: {
$subscribe: {
@@ -178,9 +169,6 @@
return this.user && this.user.darkMode;
},
},
components: {
ToolbarLayout,
},
data(){ return {
showApiKey: false,
signOutBusy: false,

View File

@@ -1,6 +1,5 @@
<template>
<toolbar-layout>
<span slot="toolbar">Characters</span>
<div>
<v-card class="ma-4">
<v-list v-if="CreaturesWithNoParty.length">
<v-list-tile
@@ -9,21 +8,21 @@
:to="character.url"
>
<v-list-tile-avatar :color="character.color">
<img
<img
v-if="character.picture"
:src="character.picture"
alt="character.name"
>
<template v-else>
{{character.initial}}
</template>
>
<template v-else>
{{ character.initial }}
</template>
</v-list-tile-avatar>
<v-list-tile-content>
<v-list-tile-title>
{{character.name}}
{{ character.name }}
</v-list-tile-title>
<v-list-tile-sub-title>
{{character.alignment}} {{character.gender}} {{character.race}}
{{ character.alignment }} {{ character.gender }} {{ character.race }}
</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
@@ -33,7 +32,9 @@
v-for="party in parties"
:key="party._id"
>
<div slot="header">{{party.name}}</div>
<div slot="header">
{{ party.name }}
</div>
<v-card>
<v-list>
<v-list-tile
@@ -41,7 +42,10 @@
:key="character._id"
>
<v-list-tile-avatar>
<img :src="character.picture" alt="character.name">
<img
:src="character.picture"
alt="character.name"
>
</v-list-tile-avatar>
</v-list-tile>
</v-list>
@@ -50,104 +54,109 @@
</v-expansion-panel>
</v-card>
<v-speed-dial
v-model="fab"
fixed
bottom
right
transition="slide-y-reverse-transition"
v-model="fab"
>
<v-btn
slot="activator"
v-model="fab"
color="accent"
fab
v-model="fab"
>
<v-icon>add</v-icon>
<v-icon>close</v-icon>
</v-btn>
<labeled-fab icon="face" label="New Character" @click="insertCharacter"></labeled-fab>
<labeled-fab icon="group" label="New Party"></labeled-fab>
<labeled-fab
icon="face"
label="New Character"
@click="insertCharacter"
/>
<labeled-fab
icon="group"
label="New Party"
/>
</v-speed-dial>
</toolbar-layout>
</div>
</template>
<script>
import Creatures, {insertCreature} from '/imports/api/creature/Creatures.js';
import Parties from '/imports/api/campaign/Parties.js';
import store from "/imports/ui/vuexStore.js";
import ToolbarLayout from "/imports/ui/layouts/ToolbarLayout.vue";
import LabeledFab from "/imports/ui/components/LabeledFab.vue";
import CharacterCreationDialog from "/imports/ui/creature/character/CharacterCreationDialog.vue";
import Creatures, {insertCreature} from '/imports/api/creature/Creatures.js';
import Parties from '/imports/api/campaign/Parties.js';
import LabeledFab from '/imports/ui/components/LabeledFab.vue';
const characterTransform = function(char){
char.url = `\/character\/${char._id}\/${char.urlName || "-"}`;
char.initial = char.name && char.name[0] || "?";
char.url = `/character/${char._id}/${char.urlName || '-'}`;
char.initial = char.name && char.name[0] || '?';
return char;
};
export default {
components: {
LabeledFab,
},
data(){ return{
fab: false,
}},
meteor: {
$subscribe: {
"characterList": [],
'characterList': [],
},
parties(){
const userId = Meteor.userId();
let parties = Parties.find(
{owner: Meteor.userId()},
{sort: {name: 1}},
).map(party => {
{owner: userId},
{sort: {name: 1}},
).map(party => {
party.characterDocs = Creatures.find(
{
_id: {$in: party.Creatures},
$or: [{readers: userId}, {writers: userId}, {owner: userId}],
}, {
{
_id: {$in: party.Creatures},
$or: [{readers: userId}, {writers: userId}, {owner: userId}],
}, {
sort: {name: 1},
}
).map(characterTransform);
).map(characterTransform);
return party;
});
return parties;
},
CreaturesWithNoParty() {
var userId = Meteor.userId();
var charArrays = Parties.find({owner: userId}).map(p => p.Creatures);
var partyChars = _.uniq(_.flatten(charArrays));
return Creatures.find(
{
_id: {$nin: partyChars},
$or: [{readers: userId}, {writers: userId}, {owner: userId}],
},
{sort: {name: 1}}
).map(characterTransform);
},
var userId = Meteor.userId();
var charArrays = Parties.find({owner: userId}).map(p => p.Creatures);
var partyChars = _.uniq(_.flatten(charArrays));
return Creatures.find(
{
_id: {$nin: partyChars},
$or: [{readers: userId}, {writers: userId}, {owner: userId}],
},
{sort: {name: 1}}
).map(characterTransform);
},
},
methods: {
insertCharacter(){
insertCreature.call((error, result) => {
if (error){
console.error(error);
} else {
this.$router.push({ path: `/character/${result}`})
}
});
insertCreature.call((error, result) => {
if (error){
console.error(error);
} else {
this.$router.push({ path: `/character/${result}`})
}
});
/*
store.commit("pushDialogStack", {
store.commit("pushDialogStack", {
component: CharacterCreationDialog,
data: {},
element: undefined,
returnElement: undefined,
callback(result){
if (!result) return;
if (!result) return;
insertCreature.call(result);
},
});
*/
*/
},
},
components: {
ToolbarLayout,
LabeledFab,
}
};
</script>

View File

@@ -1,5 +1,9 @@
<template>
<character-sheet show-menu-button :creature-id="$route.params.id" />
<character-sheet
show-menu-button
:creature-id="$route.params.id"
:tabs="tabs"
/>
</template>
<script>
@@ -8,5 +12,11 @@ export default {
components: {
CharacterSheet,
},
props: {
tabs: {
type: Number,
required: true,
},
},
}
</script>

View File

@@ -0,0 +1,20 @@
<template>
<div>
<div slot="toolbar">
Friends
</div>
<v-sheet>
<h1>
Friends
</h1>
<v-btn
fixed
bottom
right
fab
>
<v-icon>add</v-icon>
</v-btn>
</v-sheet>
</div>
</template>

View File

@@ -1,8 +1,5 @@
<template>
<toolbar-layout>
<div slot="toolbar">
DiceCloud
</div>
<div>
<div class="content">
<section>
<v-parallax
@@ -195,15 +192,11 @@
</v-layout>
</section>
</div>
</toolbar-layout>
</div>
</template>
<script>
import ToolbarLayout from '/imports/ui/layouts/ToolbarLayout.vue';
export default {
components: {
ToolbarLayout,
},
meteor: {
signedIn(){
return Meteor.userId();

View File

@@ -1,20 +1,15 @@
<template lang="html">
<toolbar-layout>
<template slot="toolbar">
Libraries
</template>
<v-card class="ma-4">
<library-and-node/>
</v-card>
</toolbar-layout>
<div>
<v-card class="ma-4">
<library-and-node />
</v-card>
</div>
</template>
<script>
import ToolbarLayout from '/imports/ui/layouts/ToolbarLayout.vue';
import LibraryAndNode from '/imports/ui/library/LibraryAndNode.vue';
export default {
components: {
ToolbarLayout,
LibraryAndNode,
},
};

View File

@@ -1,8 +1,5 @@
<template>
<toolbar-layout>
<div slot="toolbar">
Not Found
</div>
<div>
<v-layout
align-center
justify-center
@@ -11,14 +8,5 @@
No page was found for this address
</h1>
</v-layout>
</toolbar-layout>
</div>
</template>
<script>
import ToolbarLayout from '/imports/ui/layouts/ToolbarLayout.vue';
export default {
components: {
ToolbarLayout,
}
}
</script>

View File

@@ -1,22 +1,10 @@
<template lang="html">
<toolbar-layout>
<div slot="toolbar">
Not yet implemented
</div>
<v-alert
:value="true"
type="info"
>
This page is not available in this version of the alpha.
</v-alert>
</toolbar-layout>
<div>
<v-alert
:value="true"
type="info"
>
This page is not available in this version of the alpha.
</v-alert>
</div>
</template>
<script>
import ToolbarLayout from '/imports/ui/layouts/ToolbarLayout.vue';
export default {
components: {
ToolbarLayout,
},
};
</script>

View File

@@ -1,8 +1,5 @@
<template>
<toolbar-layout>
<div slot="toolbar">
Patreon tier not high enough
</div>
<div>
<v-layout
column
align-center
@@ -15,16 +12,11 @@
You need to pledge at least $5 to use this beta.
</h2>
</v-layout>
</toolbar-layout>
</div>
</template>
<script>
import ToolbarLayout from '/imports/ui/layouts/ToolbarLayout.vue';
export default {
components: {
ToolbarLayout,
},
meteor: {
entitledDollars(){
let user = Meteor.user();

View File

@@ -1,123 +1,134 @@
<template>
<ToolbarLayout>
<div slot="toolbar">Sign Up</div>
<v-form ref="form" class="mt-4">
<v-layout column align-center>
<v-img
src="crown-dice-logo-cropped-transparent.png"
width="120px"
class="ma-3"></v-img>
<v-text-field
type="text"
label="Email"
v-model="email"
:rules="emailRules"
@keyup.enter="submit"
required
></v-text-field>
<v-text-field
type="text"
label="Username"
v-model="username"
:rules="usernameRules"
@keyup.enter="submit"
required
></v-text-field>
<v-text-field
type="password"
label="Password"
v-model="password"
:rules="passwordRules"
@keyup.enter="submit"
required
></v-text-field>
<v-text-field
type="password"
label="Password Again"
v-model="password2"
:rules="password2Rules"
@keyup.enter="submit"
required
></v-text-field>
<div class="error--text">
{{error}}
</div>
<v-layout row>
<v-btn
:disabled="!valid"
@click="submit"
color="accent"
>
Register
</v-btn>
</v-layout>
</v-layout>
</v-form>
<v-divider class="ma-4"></v-divider>
<v-layout column align-center>
<div class="error--text">
{{googleError}}
</div>
<v-btn color="accent" @click="googleLogin">
Register in with Google
</v-btn>
</v-layout>
</ToolbarLayout>
<div>
<div slot="toolbar">
Sign Up
</div>
<v-form
ref="form"
class="mt-4"
>
<v-layout
column
align-center
>
<v-img
src="crown-dice-logo-cropped-transparent.png"
width="120px"
class="ma-3"
/>
<v-text-field
v-model="email"
type="text"
label="Email"
:rules="emailRules"
required
@keyup.enter="submit"
/>
<v-text-field
v-model="username"
type="text"
label="Username"
:rules="usernameRules"
required
@keyup.enter="submit"
/>
<v-text-field
v-model="password"
type="password"
label="Password"
:rules="passwordRules"
required
@keyup.enter="submit"
/>
<v-text-field
v-model="password2"
type="password"
label="Password Again"
:rules="password2Rules"
required
@keyup.enter="submit"
/>
<div class="error--text">
{{ error }}
</div>
<v-layout row>
<v-btn
:disabled="!valid"
color="accent"
@click="submit"
>
Register
</v-btn>
</v-layout>
</v-layout>
</v-form>
<v-divider class="ma-4" />
<v-layout
column
align-center
>
<div class="error--text">
{{ googleError }}
</div>
<v-btn
color="accent"
@click="googleLogin"
>
Register in with Google
</v-btn>
</v-layout>
</div>
</template>
<script>
import ToolbarLayout from "/imports/ui/layouts/ToolbarLayout.vue";
import router from "/imports/ui/router.js";
export default{
data() {
return {
valid: true,
username: "",
usernameRules: [
v => !!v || "Name is required",
],
email: "",
emailRules: [
v => !!v || "Name is required",
v => /.+@.+/.test(v) || 'E-mail must be valid',
],
password: "",
passwordRules: [
v => !!v || "Password is required",
],
password2: "",
password2Rules: [
v => !!v || "Password is required",
v => v == this.password || "Passwords don't match",
],
error: "",
googleError: "",
}
},
methods: {
import router from '/imports/ui/router.js';
export default{
data() {
return {
valid: true,
username: '',
usernameRules: [
v => !!v || 'Name is required',
],
email: '',
emailRules: [
v => !!v || 'Name is required',
v => /.+@.+/.test(v) || 'E-mail must be valid',
],
password: '',
passwordRules: [
v => !!v || 'Password is required',
],
password2: '',
password2Rules: [
v => !!v || 'Password is required',
v => v == this.password || 'Passwords don\'t match',
],
error: '',
googleError: '',
}
},
methods: {
submit () {
if (this.$refs.form.validate()) {
Accounts.createUser({
username: this.username,
password: this.password,
email: this.email,
}, error => {
if (error){
this.error = error.reason;
} else {
router.push("characterList");
}
});
Accounts.createUser({
username: this.username,
password: this.password,
email: this.email,
}, error => {
if (error){
this.error = error.reason;
} else {
router.push('characterList');
}
});
}
},
googleLogin() {
Meteor.loginWithGoogle(error => {
if (error) this.googleError = error.reason;
});
},
googleLogin() {
Meteor.loginWithGoogle(error => {
if (error) this.googleError = error.reason;
});
},
},
components: {
ToolbarLayout,
},
}
}
</script>

View File

@@ -1,8 +1,5 @@
<template>
<ToolbarLayout>
<div slot="toolbar">
Sign In
</div>
<div>
<v-form
ref="form"
class="mt-4"
@@ -83,17 +80,13 @@
Sign in with Patreon
</v-btn>
</v-layout>
</ToolbarLayout>
</div>
</template>
<script>
import { Meteor } from 'meteor/meteor'
import ToolbarLayout from '/imports/ui/layouts/ToolbarLayout.vue';
import router from '/imports/ui/router.js';
export default{
components: {
ToolbarLayout,
},
data: () => ({
valid: true,
name: '',

View File

@@ -1,40 +1,62 @@
import { RouterFactory, nativeScrollBehavior } from 'meteor/akryum:vue-router2';
import { getEntitledCentsOfUser } from '/imports/api/users/Users.js';
// Components
import Home from '/imports/ui/pages/Home.vue';
import CharacterList from '/imports/ui/pages/CharacterList.vue';
import Library from '/imports/ui/pages/Library.vue';
import CharacterSheetPage from '/imports/ui/pages/CharacterSheetPage.vue';
import CharacterSheetToolbarItems from '/imports/ui/creature/character/CharacterSheetToolbarItems.vue';
import CharacterSheetToolbarExtension from '/imports/ui/creature/character/CharacterSheetToolbarExtension.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 Friends from '/imports/ui/pages/Friends.vue' ;
import Account from '/imports/ui/pages/Account.vue' ;
import NotImplemented from '/imports/ui/pages/NotImplemented.vue';
import PatreonLevelTooLow from '/imports/ui/pages/PatreonLevelTooLow.vue';
let userSubscription = Meteor.subscribe('user');
// Not found
import NotFound from '/imports/ui/pages/NotFound.vue';
// Create router instance
const routerFactory = new RouterFactory({
mode: 'history',
scrollBehavior: nativeScrollBehavior,
});
function ensurePatronTier(to, from, next){
let user = Meteor.user();
if (!user){
next('/sign-in');
return;
}
let entitledCents = user.services.patreon.entitledCents || 0;
let overrideCents = user.services.patreon.entitledCentsOverride || 0;
if (entitledCents < 500 && overrideCents < 500){
next('/patreon-level-too-low');
} else {
next();
}
function ensureLoggedIn(to, from, next){
Tracker.autorun((computation) => {
if (userSubscription.ready()){
computation.stop();
const user = Meteor.user();
if (user){
next()
} else {
next('/sign-in');
}
}
});
}
function ensurePatronTier5(to, from, next){
Tracker.autorun((computation) => {
if (userSubscription.ready()){
computation.stop();
const user = Meteor.user();
if (!user){
next('/sign-in');
return;
}
let entitledCents = getEntitledCentsOfUser(user);
if (entitledCents < 500){
next('/patreon-level-too-low');
} else {
next();
}
}
});
}
RouterFactory.configure(factory => {
@@ -42,38 +64,101 @@ RouterFactory.configure(factory => {
{
path: '/',
name: 'home',
component: Home,
components: {
default: Home,
},
meta: {
title: 'Home',
},
},{
path: '/characterList',
component: CharacterList,
beforeEnter: ensurePatronTier,
components: {
default: CharacterList,
},
meta: {
title: 'Character List',
},
beforeEnter: ensurePatronTier5,
},{
path: '/library',
component: Library,
beforeEnter: ensurePatronTier,
components: {
default: Library,
},
meta: {
title: 'Library',
},
beforeEnter: ensurePatronTier5,
},{
path: '/character/:id/:urlName',
component: CharacterSheetPage,
beforeEnter: ensurePatronTier,
components: {
default: CharacterSheetPage,
toolbarExtension: CharacterSheetToolbarExtension,
toolbarItems: CharacterSheetToolbarItems,
},
meta: {
title: 'Character Sheet',
},
beforeEnter: ensurePatronTier5,
},{
path: '/character/:id',
component: CharacterSheetPage,
beforeEnter: ensurePatronTier,
components: {
default: CharacterSheetPage,
toolbarExtension: CharacterSheetToolbarExtension,
toolbarItems: CharacterSheetToolbarItems,
},
meta: {
title: 'Character Sheet',
},
beforeEnter: ensurePatronTier5,
},{
path: '/friends',
components: {
default: Friends,
},
meta: {
title: 'Friends',
},
beforeEnter: ensureLoggedIn,
},{
path: '/sign-in',
component: SignIn,
components: {
default: SignIn,
},
meta: {
title: 'Sign In',
},
},/*{
path: '/register',
component: Register,
components: {
default: Register,
},
meta: {
title: 'Home',
},
},*/{
path: '/account',
component: Account,
components: {
default: Account,
},
meta: {
title: 'Account',
},
},{
path: '/feedback',
component: NotImplemented,
components: {
default: NotImplemented,
},
meta: {
title: 'Feedback',
},
},{
path: '/patreon-level-too-low',
component: PatreonLevelTooLow,
components: {
default: PatreonLevelTooLow,
},
meta: {
title: 'Patreon Tier Too Low',
},
},
]);
// Icon admin routes

View File

@@ -1,6 +1,6 @@
import Vue from "vue";
import Vuex from "vuex";
import dialogStackStore from "/imports/ui/dialogStack/dialogStackStore.js";
import Vue from 'vue';
import Vuex from 'vuex';
import dialogStackStore from '/imports/ui/dialogStack/dialogStackStore.js';
Vue.use(Vuex);
const store = new Vuex.Store({
@@ -10,17 +10,18 @@ const store = new Vuex.Store({
},
state: {
drawer: undefined,
darkMode: false,
pageTitle: undefined,
},
mutations: {
toggleDrawer (state) {
state.drawer = !state.drawer;
},
setDrawer(state, value){
setDrawer (state, value) {
state.drawer = value;
},
setDarkMode(state, value){
state.darkMode = value;
setPageTitle (state, value) {
state.pageTitle = value;
document.title = value;
},
},
});

View File

@@ -1,5 +1,4 @@
Accounts.oauth.registerService('patreon');
console.log('accounts-patreon');
if (Meteor.isClient) {
const loginWithPatreon = (options, callback) => {

View File

@@ -1,5 +1,4 @@
Patreon = {};
console.log('patreon-oauth');
// Request Patreon credentials for the user
// @param options {optional}
@@ -33,7 +32,6 @@ Patreon.requestCredential = (options, credentialRequestCompleteCallback) => {
const flatScope = scope.map(encodeURIComponent).join(' ');
//const flatScope = encodeURIComponent(scope.join(','));
console.log({flatScope})
const loginStyle = OAuth._loginStyle('patreon', config, options);
const loginUrl =