Started work on tabletop view
This commit is contained in:
47
app/imports/ui/creature/CreatureListTile.vue
Normal file
47
app/imports/ui/creature/CreatureListTile.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<template
|
||||
lang="html"
|
||||
functional
|
||||
>
|
||||
<v-list-tile>
|
||||
<v-list-tile-avatar :color="model.color || 'grey'">
|
||||
<img
|
||||
v-if="model.avatarPicture"
|
||||
:src="model.avatarPicture"
|
||||
:alt="model.name"
|
||||
>
|
||||
<template v-else>
|
||||
{{ model.initial }}
|
||||
</template>
|
||||
</v-list-tile-avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>
|
||||
{{ model.name }}
|
||||
</v-list-tile-title>
|
||||
<v-list-tile-sub-title>
|
||||
{{ model.alignment }} {{ model.gender }} {{ model.race }}
|
||||
</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
<v-list-tile-action v-if="selection">
|
||||
<v-checkbox
|
||||
:input-value="selected && selected.has(model._id)"
|
||||
@change="$emit('select')"
|
||||
/>
|
||||
</v-list-tile-action>
|
||||
</v-list-tile>
|
||||
</template>
|
||||
|
||||
<script type="text/javascript">
|
||||
export default {
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
selection: Boolean,
|
||||
selected: {
|
||||
type: Set,
|
||||
default: () => new Set(),
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
11
app/imports/ui/creature/character/MiniCharacterSheet.vue
Normal file
11
app/imports/ui/creature/character/MiniCharacterSheet.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<template lang="html">
|
||||
<div class="mini-character-sheet" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -11,6 +11,7 @@ import LibraryEditDialog from '/imports/ui/library/LibraryEditDialog.vue';
|
||||
import LibraryNodeCreationDialog from '/imports/ui/library/LibraryNodeCreationDialog.vue';
|
||||
import LibraryNodeDialog from '/imports/ui/library/LibraryNodeDialog.vue';
|
||||
import MoveLibraryNodeDialog from '/imports/ui/library/MoveLibraryNodeDialog.vue'
|
||||
import SelectCreaturesDialog from '/imports/ui/tabletop/SelectCreaturesDialog.vue';
|
||||
import ShareDialog from '/imports/ui/sharing/ShareDialog.vue';
|
||||
import TierTooLowDialog from '/imports/ui/user/TierTooLowDialog.vue';
|
||||
import UsernameDialog from '/imports/ui/user/UsernameDialog.vue';
|
||||
@@ -29,6 +30,7 @@ export default {
|
||||
LibraryNodeCreationDialog,
|
||||
LibraryNodeDialog,
|
||||
MoveLibraryNodeDialog,
|
||||
SelectCreaturesDialog,
|
||||
ShareDialog,
|
||||
TierTooLowDialog,
|
||||
UsernameDialog,
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
|
||||
<script>
|
||||
import Creatures from '/imports/api/creature/Creatures.js';
|
||||
import Parties from '/imports/api/campaign/Parties.js';
|
||||
import Parties from '/imports/api/creature/Parties.js';
|
||||
|
||||
export default {
|
||||
meteor: {
|
||||
@@ -135,6 +135,7 @@
|
||||
{title: 'Home', icon: 'home', to: '/'},
|
||||
{title: 'Characters', icon: 'portrait', to: '/characterList', requireLogin: true},
|
||||
{title: 'Library', icon: 'book', to: '/library', requireLogin: true},
|
||||
{title: 'Tabletops', icon: 'api', to: '/tabletops', requireLogin: true},
|
||||
//{title: 'Friends', icon: 'people', to: '/friends', requireLogin: true},
|
||||
{title: 'Feedback', icon: 'bug_report', to: '/feedback'},
|
||||
{title: 'About', icon: 'subject', to: '/about'},
|
||||
|
||||
@@ -2,30 +2,12 @@
|
||||
<div>
|
||||
<v-card class="ma-4">
|
||||
<v-list v-if="CreaturesWithNoParty.length">
|
||||
<v-list-tile
|
||||
<creature-list-tile
|
||||
v-for="character in CreaturesWithNoParty"
|
||||
:key="character._id"
|
||||
:to="character.url"
|
||||
>
|
||||
<v-list-tile-avatar :color="character.color || 'grey'">
|
||||
<img
|
||||
v-if="character.avatarPicture"
|
||||
:src="character.avatarPicture"
|
||||
:alt="character.name"
|
||||
>
|
||||
<template v-else>
|
||||
{{ character.initial }}
|
||||
</template>
|
||||
</v-list-tile-avatar>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>
|
||||
{{ character.name }}
|
||||
</v-list-tile-title>
|
||||
<v-list-tile-sub-title>
|
||||
{{ character.alignment }} {{ character.gender }} {{ character.race }}
|
||||
</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
:model="character"
|
||||
/>
|
||||
</v-list>
|
||||
<v-expansion-panel popout>
|
||||
<v-expansion-panel-content
|
||||
@@ -98,9 +80,10 @@
|
||||
|
||||
<script>
|
||||
import Creatures, {insertCreature} from '/imports/api/creature/Creatures.js';
|
||||
import Parties from '/imports/api/campaign/Parties.js';
|
||||
import Parties from '/imports/api/creature/Parties.js';
|
||||
import LabeledFab from '/imports/ui/components/LabeledFab.vue';
|
||||
import { getUserTier } from '/imports/api/users/patreon/tiers.js';
|
||||
import CreatureListTile from '/imports/ui/creature/CreatureListTile.vue';
|
||||
|
||||
const characterTransform = function(char){
|
||||
char.url = `/character/${char._id}/${char.urlName || '-'}`;
|
||||
@@ -110,6 +93,7 @@
|
||||
export default {
|
||||
components: {
|
||||
LabeledFab,
|
||||
CreatureListTile,
|
||||
},
|
||||
data(){ return{
|
||||
fab: false,
|
||||
|
||||
46
app/imports/ui/pages/Tabletop.vue
Normal file
46
app/imports/ui/pages/Tabletop.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<template lang="html">
|
||||
<div
|
||||
class="tabletop-page"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<div
|
||||
v-if="!this.$subReady.tabletop"
|
||||
class="layout column align-center justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<v-progress-circular indeterminate />
|
||||
</div>
|
||||
<tabletop-component
|
||||
v-else-if="tabletop"
|
||||
:model="tabletop"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
class="pa-4"
|
||||
>
|
||||
<p>This tabletop was not found</p>
|
||||
<p>Either it does not exist, or you do not have permission to view it</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Tabletops from '/imports/api/tabletop/Tabletops.js';
|
||||
import TabletopComponent from '/imports/ui/tabletop/TabletopComponent.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TabletopComponent,
|
||||
},
|
||||
meteor: {
|
||||
tabletop(){
|
||||
return Tabletops.findOne(this.$route.params.id);
|
||||
},
|
||||
$subscribe: {
|
||||
'tabletop'(){
|
||||
return [this.$route.params.id];
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
67
app/imports/ui/pages/Tabletops.vue
Normal file
67
app/imports/ui/pages/Tabletops.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template lang="html">
|
||||
<single-card-layout class="tabletops">
|
||||
<v-list
|
||||
v-if="tabletops.length"
|
||||
class="tabletops"
|
||||
>
|
||||
<v-list-tile
|
||||
v-for="tabletop in tabletops"
|
||||
:key="tabletop._id"
|
||||
:to="`/tabletop/${tabletop._id}`"
|
||||
>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>
|
||||
{{ tabletop.name || 'Unnamed Tabletop' }}
|
||||
</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
</v-list>
|
||||
<v-card-text v-else>
|
||||
You don't own or belong to any tabletops yet
|
||||
</v-card-text>
|
||||
<v-btn
|
||||
color="primary"
|
||||
fab
|
||||
fixed
|
||||
bottom
|
||||
right
|
||||
:loading="addTabletopLoading"
|
||||
@click="addTabletop"
|
||||
>
|
||||
<v-icon>add</v-icon>
|
||||
</v-btn>
|
||||
</single-card-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SingleCardLayout from '/imports/ui/layouts/SingleCardLayout.vue'
|
||||
import Tabletops, { insertTabletop } from '/imports/api/tabletop/Tabletops.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SingleCardLayout,
|
||||
},
|
||||
data(){return {
|
||||
addTabletopLoading: false,
|
||||
}},
|
||||
meteor: {
|
||||
tabletops(){
|
||||
return Tabletops.find();
|
||||
},
|
||||
$subscribe: {
|
||||
'tabletops': [],
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
addTabletop(){
|
||||
this.addTabletopLoading = true;
|
||||
insertTabletop.call(() => {
|
||||
this.addTabletopLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -20,6 +20,9 @@ import InviteSuccess from '/imports/ui/pages/InviteSuccess.vue' ;
|
||||
import InviteError from '/imports/ui/pages/InviteError.vue' ;
|
||||
import NotImplemented from '/imports/ui/pages/NotImplemented.vue';
|
||||
import PatreonLevelTooLow from '/imports/ui/pages/PatreonLevelTooLow.vue';
|
||||
import Tabletops from '/imports/ui/pages/Tabletops.vue';
|
||||
import Tabletop from '/imports/ui/pages/Tabletop.vue';
|
||||
import TabletopToolbar from '/imports/ui/tabletop/TabletopToolbar.vue';
|
||||
|
||||
let userSubscription = Meteor.subscribe('user');
|
||||
|
||||
@@ -143,6 +146,19 @@ RouterFactory.configure(factory => {
|
||||
meta: {
|
||||
title: 'Character Sheet',
|
||||
},
|
||||
},{
|
||||
path: '/tabletops',
|
||||
name: 'tabletops',
|
||||
component: Tabletops,
|
||||
beforeEnter: ensureLoggedIn,
|
||||
},{
|
||||
path: '/tabletop/:id',
|
||||
name: 'tabletop',
|
||||
components: {
|
||||
default: Tabletop,
|
||||
toolbar: TabletopToolbar,
|
||||
},
|
||||
beforeEnter: ensureLoggedIn,
|
||||
},{
|
||||
path: '/friends',
|
||||
components: {
|
||||
|
||||
63
app/imports/ui/tabletop/SelectCreaturesDialog.vue
Normal file
63
app/imports/ui/tabletop/SelectCreaturesDialog.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<template lang="html">
|
||||
<dialog-base>
|
||||
<v-toolbar-title slot="toolbar">
|
||||
Add Characters
|
||||
</v-toolbar-title>
|
||||
<v-list>
|
||||
<creature-list-tile
|
||||
v-for="creature in creatures"
|
||||
:key="creature._id"
|
||||
:model="creature"
|
||||
:selected="selected"
|
||||
selection
|
||||
@select="toggleSelect(creature._id)"
|
||||
/>
|
||||
</v-list>
|
||||
<template slot="actions">
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
flat
|
||||
color="primary"
|
||||
@click="$store.dispatch('popDialogStack', selected)"
|
||||
>
|
||||
Add characters
|
||||
</v-btn>
|
||||
</template>
|
||||
</dialog-base>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
|
||||
import Creatures from '/imports/api/creature/Creatures.js';
|
||||
import CreatureListTile from '/imports/ui/creature/CreatureListTile.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
DialogBase,
|
||||
CreatureListTile,
|
||||
},
|
||||
props: {
|
||||
startingSelection: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
data(){return {
|
||||
selected: new Set(this.startingSelection),
|
||||
}},
|
||||
meteor: {
|
||||
creatures(){
|
||||
return Creatures.find({});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggleSelect(id){
|
||||
let hadId = this.selected.delete(id);
|
||||
if (!hadId) this.selected.add(id);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
51
app/imports/ui/tabletop/TabletopActionCards.vue
Normal file
51
app/imports/ui/tabletop/TabletopActionCards.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template lang="html">
|
||||
<div class="action-cards">
|
||||
<action-card
|
||||
v-for="action in actions"
|
||||
:key="action._id"
|
||||
:model="action"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
|
||||
import ActionCard from '/imports/ui/properties/components/actions/ActionCard.vue';
|
||||
|
||||
function getProperties(ancestorId, type){
|
||||
if (!ancestorId) return [];
|
||||
return getActiveProperties({
|
||||
ancestorId,
|
||||
filter: {type},
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ActionCard,
|
||||
},
|
||||
props: {
|
||||
creatureId: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
data(){ return {
|
||||
actionType: 'action',
|
||||
}},
|
||||
meteor: {
|
||||
actions(){
|
||||
return getProperties(this.creatureId, 'action');
|
||||
},
|
||||
attacks(){
|
||||
return getProperties(this.creatureId, 'attack');
|
||||
},
|
||||
spells(){
|
||||
return getProperties(this.creatureId, 'spell');
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
100
app/imports/ui/tabletop/TabletopComponent.vue
Normal file
100
app/imports/ui/tabletop/TabletopComponent.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<template lang="html">
|
||||
<div class="tabletop">
|
||||
<section class="initiative-row layout row center">
|
||||
<tabletop-creature-card
|
||||
v-for="creature in creatures"
|
||||
:key="creature._id"
|
||||
:model="creature"
|
||||
/>
|
||||
<v-card
|
||||
class="layout column justify-center align-center"
|
||||
style="height: 162px; width: 100px;"
|
||||
data-id="select-creatures"
|
||||
hover
|
||||
@click="addCreature"
|
||||
>
|
||||
<div class="flex layout row justify-center align-center">
|
||||
<v-icon>add</v-icon>
|
||||
</div>
|
||||
<v-card-title>
|
||||
Add creature
|
||||
</v-card-title>
|
||||
</v-card>
|
||||
</section>
|
||||
<section class="play-area">
|
||||
<tabletop-map />
|
||||
<tabletop-log />
|
||||
</section>
|
||||
<section class="action-row">
|
||||
<mini-character-sheet />
|
||||
<tabletop-action-cards />
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { addCreaturesToTabletop } from '/imports/api/tabletop/Tabletops.js';
|
||||
|
||||
import TabletopCreatureCard from '/imports/ui/tabletop/TabletopCreatureCard.vue';
|
||||
import TabletopMap from '/imports/ui/tabletop/TabletopMap.vue';
|
||||
import TabletopLog from '/imports/ui/tabletop/TabletopLog.vue';
|
||||
import Creatures from '/imports/api/creature/Creatures.js';
|
||||
import TabletopActionCards from '/imports/ui/tabletop/TabletopActionCards.vue';
|
||||
import MiniCharacterSheet from '/imports/ui/creature/character/MiniCharacterSheet.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TabletopCreatureCard,
|
||||
TabletopMap,
|
||||
TabletopLog,
|
||||
TabletopActionCards,
|
||||
MiniCharacterSheet,
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data(){ return {
|
||||
activeCreature: undefined,
|
||||
}},
|
||||
meteor: {
|
||||
$subscribe:{
|
||||
'tabletop'(){
|
||||
return [this.model._id];
|
||||
},
|
||||
},
|
||||
creatures(){
|
||||
return Creatures.find({tabletop: this.model._id});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
addCreature(){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'select-creatures-dialog',
|
||||
elementId: 'select-creatures',
|
||||
data: {
|
||||
startingSelection: this.creatures.map(c => c._id),
|
||||
},
|
||||
callback: (characterSet) => {
|
||||
if (!characterSet) return;
|
||||
addCreaturesToTabletop.call({
|
||||
tabletopId: this.model._id,
|
||||
creatureIds: Array.from(characterSet),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.initiative-row > .v-card {
|
||||
flex-grow: 0;
|
||||
height: 162px;
|
||||
width: 100px;
|
||||
margin: 4px;
|
||||
}
|
||||
</style>
|
||||
24
app/imports/ui/tabletop/TabletopCreatureCard.vue
Normal file
24
app/imports/ui/tabletop/TabletopCreatureCard.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<template lang="html">
|
||||
<v-card>
|
||||
<v-img
|
||||
:src="model.picture"
|
||||
aspect-ratio="1"
|
||||
position="top center"
|
||||
/>
|
||||
<v-card-title>{{ model.name }}</v-card-title>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
11
app/imports/ui/tabletop/TabletopLog.vue
Normal file
11
app/imports/ui/tabletop/TabletopLog.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<template lang="html">
|
||||
<div class="tabletop-log" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
11
app/imports/ui/tabletop/TabletopMap.vue
Normal file
11
app/imports/ui/tabletop/TabletopMap.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<template lang="html">
|
||||
<div class="tabletop-map" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
29
app/imports/ui/tabletop/TabletopToolbar.vue
Normal file
29
app/imports/ui/tabletop/TabletopToolbar.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<template lang="html">
|
||||
<v-toolbar
|
||||
app
|
||||
color="secondary"
|
||||
dark
|
||||
dense
|
||||
>
|
||||
<v-toolbar-side-icon @click="toggleDrawer" />
|
||||
<v-toolbar-title>
|
||||
Tabletop
|
||||
</v-toolbar-title>
|
||||
<v-spacer />
|
||||
</v-toolbar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations } from 'vuex';
|
||||
|
||||
export default {
|
||||
methods: {
|
||||
...mapMutations([
|
||||
'toggleDrawer',
|
||||
]),
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
Reference in New Issue
Block a user