Added character creation dialog
This commit is contained in:
294
app/imports/ui/character/CharacterCreationDialog.vue
Normal file
294
app/imports/ui/character/CharacterCreationDialog.vue
Normal file
@@ -0,0 +1,294 @@
|
||||
<template>
|
||||
<dialog-base>
|
||||
<template slot="toolbar">New Character</template>
|
||||
<v-stepper v-model="step" class="no-shadow">
|
||||
<v-stepper-header class="no-shadow">
|
||||
<v-stepper-step :complete="step > 1" step="1">
|
||||
Name
|
||||
</v-stepper-step>
|
||||
<v-divider></v-divider>
|
||||
<v-stepper-step :complete="step > 2" step="2">
|
||||
Ability Scores
|
||||
</v-stepper-step>
|
||||
<v-divider></v-divider>
|
||||
<v-stepper-step :complete="step > 3" step="3">
|
||||
Class
|
||||
</v-stepper-step>
|
||||
</v-stepper-header>
|
||||
|
||||
<v-stepper-items>
|
||||
<v-stepper-content step="1">
|
||||
<v-text-field label="Name" v-model="name"></v-text-field>
|
||||
<v-text-field label="Gender" v-model="gender"></v-text-field>
|
||||
<v-text-field label="Alignment" v-model="alignment"></v-text-field>
|
||||
</v-stepper-content>
|
||||
<v-stepper-content step="2">
|
||||
<v-text-field label="Race" v-model="race"></v-text-field>
|
||||
<v-layout row justify-center align-center>
|
||||
<h3>Point Cost:</h3>
|
||||
<h1 class="ml-2" :class="cost > 27 ? 'error--text' : ''">{{cost}}</h1>
|
||||
<span class="ml-1">/27</span>
|
||||
</v-layout>
|
||||
<table class="point-buy-table mt-2">
|
||||
<thead>
|
||||
<tr class="font-weight-bold">
|
||||
<td></td>
|
||||
<td>Base Values</td>
|
||||
<td>Race Bonus</td>
|
||||
<td>Score</td>
|
||||
<td>Modifier</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>Strength</td>
|
||||
<td><v-text-field
|
||||
type="number"
|
||||
height="20"
|
||||
reverse
|
||||
v-model.number="baseStrength"
|
||||
min="8"
|
||||
max="15">
|
||||
</v-text-field></td>
|
||||
<td><v-text-field
|
||||
type="number"
|
||||
height="20"
|
||||
reverse
|
||||
v-model.number="strengthBonus">
|
||||
</v-text-field></td>
|
||||
<td>{{baseStrength + strengthBonus}}</td>
|
||||
<td>{{mod(baseStrength + strengthBonus)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Dexterity</td>
|
||||
<td><v-text-field
|
||||
type="number"
|
||||
height="20"
|
||||
reverse
|
||||
v-model.number="baseDexterity"
|
||||
min="8"
|
||||
max="15">
|
||||
</v-text-field></td>
|
||||
<td><v-text-field
|
||||
type="number"
|
||||
height="20"
|
||||
reverse
|
||||
v-model.number="dexterityBonus">
|
||||
</v-text-field></td>
|
||||
<td>{{baseDexterity + dexterityBonus}}</td>
|
||||
<td>{{mod(baseDexterity + dexterityBonus)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Constitution</td>
|
||||
<td><v-text-field
|
||||
type="number"
|
||||
height="20"
|
||||
reverse
|
||||
v-model.number="baseConstitution"
|
||||
min="8"
|
||||
max="15">
|
||||
</v-text-field></td>
|
||||
<td><v-text-field
|
||||
type="number"
|
||||
height="20"
|
||||
reverse
|
||||
v-model.number="constitutionBonus">
|
||||
</v-text-field></td>
|
||||
<td>{{baseConstitution + constitutionBonus}}</td>
|
||||
<td>{{mod(baseConstitution + constitutionBonus)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Intelligence</td>
|
||||
<td><v-text-field
|
||||
type="number"
|
||||
height="20"
|
||||
reverse
|
||||
v-model.number="baseIntelligence"
|
||||
min="8"
|
||||
max="15">
|
||||
</v-text-field></td>
|
||||
<td><v-text-field
|
||||
type="number"
|
||||
height="20"
|
||||
reverse
|
||||
v-model.number="intelligenceBonus">
|
||||
</v-text-field></td>
|
||||
<td>{{baseIntelligence + intelligenceBonus}}</td>
|
||||
<td>{{mod(baseIntelligence + intelligenceBonus)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Wisdom</td>
|
||||
<td><v-text-field
|
||||
type="number"
|
||||
height="20"
|
||||
reverse
|
||||
v-model.number="baseWisdom"
|
||||
min="8"
|
||||
max="15">
|
||||
</v-text-field></td>
|
||||
<td><v-text-field
|
||||
type="number"
|
||||
height="20"
|
||||
reverse
|
||||
v-model.number="wisdomBonus">
|
||||
</v-text-field></td>
|
||||
<td>{{baseWisdom + wisdomBonus}}</td>
|
||||
<td>{{mod(baseWisdom + wisdomBonus)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Charisma</td>
|
||||
<td><v-text-field
|
||||
type="number"
|
||||
height="20"
|
||||
reverse
|
||||
v-model.number="baseCharisma"
|
||||
min="8"
|
||||
max="15">
|
||||
</v-text-field></td>
|
||||
<td><v-text-field
|
||||
type="number"
|
||||
height="20"
|
||||
reverse
|
||||
v-model.number="charismaBonus">
|
||||
</v-text-field></td>
|
||||
<td>{{baseCharisma + charismaBonus}}</td>
|
||||
<td>{{mod(baseCharisma + charismaBonus)}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</v-stepper-content>
|
||||
<v-stepper-content step="3">
|
||||
<v-text-field
|
||||
label="Class"
|
||||
v-model="cls"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-select
|
||||
:items="hitDiceItems"
|
||||
label="Hit Dice"
|
||||
v-model="hitDice">
|
||||
</v-select>
|
||||
</v-text-field>
|
||||
</v-stepper-content>
|
||||
</v-stepper-items>
|
||||
</v-stepper>
|
||||
<template slot="actions">
|
||||
<v-btn flat @click="$emit('pop')">Cancel</v-btn>
|
||||
<v-btn flat @click="step--" v-if="step > 1">Back</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="accent" @click="step++" v-if="step < 3">Next</v-btn>
|
||||
<v-btn
|
||||
:flat="step < 3"
|
||||
:color="step < 3? '' : 'accent'"
|
||||
@click="submit">
|
||||
Create
|
||||
</v-btn>
|
||||
</template>
|
||||
</dialog-base>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DialogBase from "/imports/ui/dialogStack/DialogBase.vue";
|
||||
const getCost = function(score){
|
||||
const costs = {
|
||||
8: 0,
|
||||
9: 1,
|
||||
10: 2,
|
||||
11: 3,
|
||||
12: 4,
|
||||
13: 5,
|
||||
14: 7,
|
||||
15: 9,
|
||||
};
|
||||
if (costs[score]){
|
||||
return costs[score];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
export default {
|
||||
data(){return {
|
||||
step: 1,
|
||||
name: "New Character",
|
||||
gender: "",
|
||||
alignment: "",
|
||||
race: "",
|
||||
baseStrength: 10,
|
||||
baseDexterity: 10,
|
||||
baseConstitution: 10,
|
||||
baseIntelligence: 10,
|
||||
baseWisdom: 10,
|
||||
baseCharisma: 10,
|
||||
strengthBonus: 0,
|
||||
dexterityBonus: 0,
|
||||
constitutionBonus: 0,
|
||||
intelligenceBonus: 0,
|
||||
wisdomBonus: 0,
|
||||
charismaBonus: 0,
|
||||
hitDiceItems: ["d6", "d8", "d10", "d12"],
|
||||
hitDice: "",
|
||||
cls: "",
|
||||
}},
|
||||
methods: {
|
||||
mod(score){
|
||||
let mod = Math.floor((score - 10) / 2);
|
||||
if (mod >= 0) {
|
||||
return `+${mod}`;
|
||||
} else {
|
||||
return `${mod}`;
|
||||
}
|
||||
},
|
||||
submit(){
|
||||
let char = {
|
||||
name: this.name,
|
||||
gender: this.gender,
|
||||
alignment: this.alignment,
|
||||
race: this.race,
|
||||
baseStrength: this.baseStrength,
|
||||
baseDexterity: this.baseDexterity,
|
||||
baseConstitution: this.baseConstitution,
|
||||
baseIntelligence: this.baseIntelligence,
|
||||
baseWisdom: this.baseWisdom,
|
||||
baseCharisma: this.baseCharisma,
|
||||
strengthBonus: this.strengthBonus,
|
||||
dexterityBonus: this.dexterityBonus,
|
||||
constitutionBonus: this.constitutionBonus,
|
||||
intelligenceBonus: this.intelligenceBonus,
|
||||
wisdomBonus: this.wisdomBonus,
|
||||
charismaBonus: this.charismaBonus,
|
||||
hitDice: this.hitDice,
|
||||
cls: this.cls,
|
||||
};
|
||||
this.$emit("pop", char);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
cost(){
|
||||
return [
|
||||
this.baseStrength,
|
||||
this.baseDexterity,
|
||||
this.baseConstitution,
|
||||
this.baseIntelligence,
|
||||
this.baseWisdom,
|
||||
this.baseCharisma,
|
||||
].map(getCost)
|
||||
.reduce((memo, score) => memo + score, 0);
|
||||
},
|
||||
},
|
||||
components: {
|
||||
DialogBase,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.no-shadow {
|
||||
box-shadow: none;
|
||||
}
|
||||
.point-buy-table {
|
||||
width: 100%;
|
||||
}
|
||||
.point-buy-table td {
|
||||
text-align: center;
|
||||
padding: 0 8px 0 8px;
|
||||
max-width: 50px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<v-btn fab small>
|
||||
<v-btn fab small @click="$emit('click')">
|
||||
<v-icon>
|
||||
{{icon}}
|
||||
</v-icon>
|
||||
|
||||
@@ -1,13 +1,39 @@
|
||||
<template>
|
||||
<v-card>
|
||||
<v-toolbar color="primary" dark>
|
||||
<slot name="toolbar"></slot>
|
||||
</v-toolbar>
|
||||
<v-layout>
|
||||
<slot></slot>
|
||||
</v-layout>
|
||||
<v-card-actions>
|
||||
<slot name="actions"></slot>
|
||||
</v-card-actions>
|
||||
<v-layout column style="height: 100%;">
|
||||
<v-toolbar color="primary" dark class="base-dialog-toolbar" :flat="!offsetTop">
|
||||
<slot name="toolbar"></slot>
|
||||
</v-toolbar>
|
||||
<div id="base-dialog-body" v-scroll:#base-dialog-body="onScroll">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<v-card-actions>
|
||||
<slot name="actions"></slot>
|
||||
</v-card-actions>
|
||||
</v-layout>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data(){ return {
|
||||
offsetTop: 0,
|
||||
}},
|
||||
methods: {
|
||||
onScroll(e){
|
||||
this.offsetTop = e.target.scrollTop
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.base-dialog-toolbar {
|
||||
z-index: 1;
|
||||
border-radius: 2px 2px 0 0;
|
||||
}
|
||||
#base-dialog-body {
|
||||
flex-grow: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
class="dialog"
|
||||
:style="getDialogStyle(index)"
|
||||
>
|
||||
<component :is="dialog.component" :data="dialog.data"></component>
|
||||
<component :is="dialog.component" :data="dialog.data" @pop="popDialogStack($event)"></component>
|
||||
</div>
|
||||
</transition-group>
|
||||
</v-layout>
|
||||
@@ -32,8 +32,8 @@
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
popDialogStack(){
|
||||
store.dispatch("popDialogStack");
|
||||
popDialogStack(result){
|
||||
store.dispatch("popDialogStack", result);
|
||||
},
|
||||
backdropClicked(event){
|
||||
if (event.target === event.currentTarget) this.popDialogStack();
|
||||
@@ -61,8 +61,8 @@
|
||||
}
|
||||
.dialog-sizer {
|
||||
position: relative;
|
||||
height: 500px;
|
||||
width: 500px;
|
||||
height: 600px;
|
||||
width: 600px;
|
||||
z-index: 5;
|
||||
flex: initial;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ dialogStack.dialogs = [];
|
||||
const dialogStackStore = {
|
||||
state: {
|
||||
dialogs: [],
|
||||
currentResult: null,
|
||||
},
|
||||
mutations: {
|
||||
pushDialogStack(state, {component, data, element, returnElement, callback}){
|
||||
@@ -24,15 +25,18 @@ const dialogStackStore = {
|
||||
updateHistory();
|
||||
},
|
||||
popDialogStackMutation (state, result){
|
||||
console.log({popped: result});
|
||||
const dialog = state.dialogs.pop();
|
||||
state.currentResult = null;
|
||||
updateHistory();
|
||||
if (!dialog) return;
|
||||
dialog.callback && dialog.callback(result);
|
||||
if (dialog.callback) dialog.callback(result);
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
popDialogStack(context, result){
|
||||
if (history && history.state && history.state.openDialogs){
|
||||
context.state.currentResult = result;
|
||||
history.back();
|
||||
} else {
|
||||
context.commit("popDialogStackMutation", result)
|
||||
|
||||
@@ -5,7 +5,7 @@ if (window){
|
||||
let state = event.state;
|
||||
let numDialogs = store.state.dialogStack.dialogs.length;
|
||||
if (_.isFinite(state.openDialogs) && numDialogs > state.openDialogs){
|
||||
store.commit("popDialogStackMutation");
|
||||
store.commit("popDialogStackMutation", store.state.dialogStack.currentResult);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -65,15 +65,17 @@
|
||||
<v-icon>add</v-icon>
|
||||
<v-icon>close</v-icon>
|
||||
</v-btn>
|
||||
<labeled-fab icon="face" label="New Character"></labeled-fab>
|
||||
<labeled-fab icon="face" label="New Character" @click="insertCharacter"></labeled-fab>
|
||||
<labeled-fab icon="group" label="New Party"></labeled-fab>
|
||||
</v-speed-dial>
|
||||
</toolbar-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
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/character/CharacterCreationDialog.vue";
|
||||
|
||||
const characterTransform = function(char){
|
||||
char.url = `\/character\/${char._id}\/${char.urlName || "-"}`;
|
||||
@@ -118,6 +120,20 @@
|
||||
).map(characterTransform);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
insertCharacter(e){
|
||||
console.log(e);
|
||||
store.commit("pushDialogStack", {
|
||||
component: CharacterCreationDialog,
|
||||
data: {},
|
||||
element: undefined,
|
||||
returnElement: undefined,
|
||||
callback(result){
|
||||
console.log({result});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
components: {
|
||||
ToolbarLayout,
|
||||
LabeledFab,
|
||||
|
||||
Reference in New Issue
Block a user