New client spell fixes (#8974)

* Prevented spells menu from apearing below lvl 11

* Expanding clickable casting area

* Persisted spell drawer close

* Added edit form modal to party

* Added spell toggle

* Added markdown notification

* Prevented casting on challenge and group tasks locally

* Quick fix for self cast

* Fixed lint issue
This commit is contained in:
Keith Holliday
2017-08-21 23:04:56 -06:00
committed by GitHub
parent acaed1ef0e
commit 798d0ab82b
8 changed files with 159 additions and 116 deletions

View File

@@ -1,5 +1,5 @@
<template lang="pug"> <template lang="pug">
#app #app(:class='{"casting-spell": castingSpell}')
notifications notifications
router-view(v-if="!isUserLoggedIn || isStaticPage") router-view(v-if="!isUserLoggedIn || isStaticPage")
template(v-else) template(v-else)
@@ -15,6 +15,12 @@
app-footer app-footer
</template> </template>
<style scoped>
.casting-spell {
cursor: crosshair;
}
</style>
<script> <script>
import axios from 'axios'; import axios from 'axios';
import AppMenu from './components/appMenu'; import AppMenu from './components/appMenu';
@@ -42,6 +48,9 @@ export default {
isStaticPage () { isStaticPage () {
return this.$route.meta.requiresLogin === false ? true : false; return this.$route.meta.requiresLogin === false ? true : false;
}, },
castingSpell () {
return this.$store.state.spellOptions.castingSpell;
},
}, },
created () { created () {
// Set up Error interceptors // Set up Error interceptors

View File

@@ -190,7 +190,7 @@ export default {
return result; return result;
}, },
castEnd (e) { castEnd (e) {
if (!this.$store.state.castingSpell) return; if (!this.$store.state.spellOptions.castingSpell) return;
this.$root.$emit('castEnd', this.member, 'user', e); this.$root.$emit('castEnd', this.member, 'user', e);
}, },
}, },

View File

@@ -1,5 +1,6 @@
<template lang="pug"> <template lang="pug">
.row(v-if="group") .row(v-if="group")
group-form-modal(v-if='isParty')
invite-modal(:group='this.group') invite-modal(:group='this.group')
start-quest-modal(:group='this.group') start-quest-modal(:group='this.group')
.col-8.standard-page .col-8.standard-page

View File

@@ -1,5 +1,5 @@
<template lang="pug"> <template lang="pug">
div div(v-if='user.stats.lvl > 10')
div.dragInfo.mouse(ref="clickPotionInfo", v-if="potionClickMode") div.dragInfo.mouse(ref="clickPotionInfo", v-if="potionClickMode")
.spell.col-12.row .spell.col-12.row
.col-8.details .col-8.details
@@ -10,7 +10,9 @@ div
drawer(:title="$t('spells')", drawer(:title="$t('spells')",
v-if='user.stats.class && !user.preferences.disableClasses', v-if='user.stats.class && !user.preferences.disableClasses',
v-mousePosition="30", @mouseMoved="mouseMoved($event)") v-mousePosition="30", @mouseMoved="mouseMoved($event)",
:openStatus='openStatus',
v-on:toggled='drawerToggled')
div(slot="drawer-slider") div(slot="drawer-slider")
.container.spell-container .container.spell-container
.row .row
@@ -181,8 +183,14 @@ export default {
}, },
computed: { computed: {
...mapState({user: 'user.data'}), ...mapState({user: 'user.data'}),
openStatus () {
return this.$store.state.spellOptions.spellDrawOpen ? 1 : 0;
},
}, },
methods: { methods: {
drawerToggled (openChanged) {
this.$store.state.spellOptions.spellDrawOpen = openChanged;
},
spellDisabled (skill) { spellDisabled (skill) {
if (skill === 'frost' && this.user.stats.buffs.streaks) { if (skill === 'frost' && this.user.stats.buffs.streaks) {
return true; return true;
@@ -211,6 +219,11 @@ export default {
return notes; return notes;
}, },
async castStart (spell) { async castStart (spell) {
if (this.$store.state.spellOptions.castingSpell) {
this.castCancel();
return;
}
if (this.user.stats.mp < spell.mana) return this.text(this.$t('notEnoughMana')); if (this.user.stats.mp < spell.mana) return this.text(this.$t('notEnoughMana'));
if (spell.immediateUse && this.user.stats.gp < spell.value) { if (spell.immediateUse && this.user.stats.gp < spell.value) {
@@ -219,9 +232,8 @@ export default {
this.potionClickMode = true; this.potionClickMode = true;
this.applyingAction = true; this.applyingAction = true;
this.$store.state.castingSpell = true; this.$store.state.spellOptions.castingSpell = true;
this.spell = spell; this.spell = spell;
document.querySelector('body').style.cursor = 'crosshair';
if (spell.target === 'self') { if (spell.target === 'self') {
this.castEnd(null, 'self'); this.castEnd(null, 'self');
@@ -236,6 +248,7 @@ export default {
let party = await this.$store.dispatch('guilds:getGroup', {groupId: 'party'}); let party = await this.$store.dispatch('guilds:getGroup', {groupId: 'party'});
party = isArray(party) ? party : []; party = isArray(party) ? party : [];
party = party.concat(this.user); party = party.concat(this.user);
this.$store.state.party.data = party;
this.castEnd(party, 'party'); this.castEnd(party, 'party');
} else if (spell.target === 'tasks') { } else if (spell.target === 'tasks') {
let tasks = this.$store.state.tasks.habits.concat(this.user.dailys) let tasks = this.$store.state.tasks.habits.concat(this.user.dailys)
@@ -250,16 +263,17 @@ export default {
} }
}, },
async castEnd (target, type) { async castEnd (target, type) {
if (!this.$store.state.castingSpell) return; if (!this.$store.state.spellOptions.castingSpell) return;
let beforeQuestProgress = this.questProgress(); let beforeQuestProgress = this.questProgress();
if (!this.applyingAction) return 'No applying action'; if (!this.applyingAction) return 'No applying action';
if (this.spell.target !== type) return this.text(this.$t('invalidTarget')); if (this.spell.target !== type) return this.text(this.$t('invalidTarget'));
if (target && target.challenge && target.challenge.id) return this.text(this.$t('invalidTarget'));
if (target && target.group && target.group.id) return this.text(this.$t('invalidTarget'));
// @TODO: just call castCancel? // @TODO: just call castCancel?
document.querySelector('body').style.cursor = 'initial'; this.$store.state.spellOptions.castingSpell = false;
this.$store.state.castingSpell = false;
this.potionClickMode = false; this.potionClickMode = false;
// @TODO: We no longer wrap the users (or at least we should not), but some common code // @TODO: We no longer wrap the users (or at least we should not), but some common code
@@ -327,7 +341,7 @@ export default {
this.applyingAction = false; this.applyingAction = false;
this.spell = null; this.spell = null;
document.querySelector('body').style.cursor = 'initial'; document.querySelector('body').style.cursor = 'initial';
this.$store.state.castingSpell = false; this.$store.state.spellOptions.castingSpell = false;
}, },
questProgress () { questProgress () {
let user = this.user; let user = this.user;

View File

@@ -1,5 +1,5 @@
<template lang="pug"> <template lang="pug">
.task .task(@click='castEnd($event, task)')
approval-header(:task='task', v-if='this.task.group.id', :group='group') approval-header(:task='task', v-if='this.task.group.id', :group='group')
.d-flex(:class="{'task-not-scoreable': isUser !== true}") .d-flex(:class="{'task-not-scoreable': isUser !== true}")
// Habits left side control // Habits left side control
@@ -379,10 +379,11 @@ export default {
if (target.tagName === 'A') { // Link if (target.tagName === 'A') { // Link
return; return;
} else if (!this.$store.state.castingSpell) { } else if (!this.$store.state.spellOptions.castingSpell) {
this.$emit('editTask', task); this.$emit('editTask', task);
} }
},
castEnd (e, task) {
this.$root.$emit('castEnd', task, 'task', e); this.$root.$emit('castEnd', task, 'task', e);
}, },
async score (direction) { async score (direction) {

View File

@@ -1,10 +1,10 @@
<template lang="pug"> <template lang="pug">
.drawer-container .drawer-container
.drawer-title(@click="open = !open") .drawer-title(@click="toggle()")
| {{title}} | {{title}}
.drawer-toggle-icon.svg-icon.icon-10(v-html="open ? icons.minimize : icons.expand", :class="{ closed: !open }") .drawer-toggle-icon.svg-icon.icon-10(v-html="isOpen ? icons.minimize : icons.expand", :class="{ closed: !isOpen }")
transition(name="slide-up", @afterLeave="adjustPagePadding", @afterEnter="adjustPagePadding") transition(name="slide-up", @afterLeave="adjustPagePadding", @afterEnter="adjustPagePadding")
.drawer-content(v-show="open") .drawer-content(v-show="isOpen")
slot(name="drawer-header") slot(name="drawer-header")
.drawer-slider .drawer-slider
slot(name="drawer-slider") slot(name="drawer-slider")
@@ -13,117 +13,117 @@
</template> </template>
<style lang="scss"> <style lang="scss">
@import '~client/assets/scss/colors.scss'; @import '~client/assets/scss/colors.scss';
.drawer-container { .drawer-container {
z-index: 19; z-index: 19;
position: fixed; position: fixed;
font-size: 12px;
font-weight: bold;
bottom: 0;
left: 19%;
right: 3%;
max-width: 80%;
@media screen and (min-width: 1241px) {
max-width: 968px;
// 16.67% is the width of the .col-2 sidebar
left: calc((100% + 16.67% - 968px) / 2);
right: 0%;
}
}
.drawer-toggle-icon {
float: right;
margin-right: 16px;
margin-top: 16px;
&.closed {
margin-top: 3px;
}
}
.drawer-title {
background-color: $gray-10;
box-shadow: 0 1px 2px 0 rgba($black, 0.2);
cursor: pointer;
border-top-right-radius: 8px;
border-top-left-radius: 8px;
text-align: center;
line-height: 1.67;
color: $white;
padding: 6px 0;
}
.drawer-content {
line-height: 1.33;
max-height: 300px;
background-color: $gray-50;
color: $gray-500;
box-shadow: 0 2px 16px 0 rgba($black, 0.3);
padding-top: 6px;
padding-left: 24px;
padding-right: 24px;
}
.drawer-tab {
&-container {
display: flex;
margin-left: 24px;
& > div {
flex: 1;
}
}
&-text {
font-size: 12px; font-size: 12px;
font-weight: bold; font-weight: bold;
line-height: 1.67; bottom: 0;
left: 19%;
right: 3%;
max-width: 80%;
@media screen and (min-width: 1241px) {
max-width: 968px;
// 16.67% is the width of the .col-2 sidebar
left: calc((100% + 16.67% - 968px) / 2);
right: 0%;
}
}
.drawer-toggle-icon {
float: right;
margin-right: 16px;
margin-top: 16px;
&.closed {
margin-top: 3px;
}
}
.drawer-title {
background-color: $gray-10;
box-shadow: 0 1px 2px 0 rgba($black, 0.2);
cursor: pointer;
border-top-right-radius: 8px;
border-top-left-radius: 8px;
text-align: center; text-align: center;
line-height: 1.67;
color: $white; color: $white;
border-bottom: 2px solid transparent; padding: 6px 0;
padding: 0px 8px 8px 8px; }
&-active { .drawer-content {
border-color: $purple-400; line-height: 1.33;
max-height: 300px;
background-color: $gray-50;
color: $gray-500;
box-shadow: 0 2px 16px 0 rgba($black, 0.3);
padding-top: 6px;
padding-left: 24px;
padding-right: 24px;
}
.drawer-tab {
&-container {
display: flex;
margin-left: 24px;
& > div {
flex: 1;
}
}
&-text {
font-size: 12px;
font-weight: bold;
line-height: 1.67;
text-align: center;
color: $white;
border-bottom: 2px solid transparent;
padding: 0px 8px 8px 8px;
&-active {
border-color: $purple-400;
}
} }
} }
}
.drawer-slider { .drawer-slider {
padding: 12px 0 0 8px; padding: 12px 0 0 8px;
overflow-x: auto; overflow-x: auto;
overflow-y: hidden; overflow-y: hidden;
white-space: nowrap; white-space: nowrap;
position: relative; position: relative;
& .message { & .message {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
top: calc(50% - 30px); top: calc(50% - 30px);
left: 24px; left: 24px;
right: 0; right: 0;
position: absolute; position: absolute;
& .content { & .content {
background-color: rgba($gray-200, 0.5); background-color: rgba($gray-200, 0.5);
border-radius: 8px; border-radius: 8px;
padding: 12px; padding: 12px;
}
} }
} }
}
.slide-up-enter-active, .slide-up-leave-active { .slide-up-enter-active, .slide-up-leave-active {
transition-property: all; transition-property: all;
transition-duration: 450ms; transition-duration: 450ms;
transition-timing-function: cubic-bezier(0.445, 0.05, 0.55, 0.95); transition-timing-function: cubic-bezier(0.445, 0.05, 0.55, 0.95);
} }
.slide-up-enter, .slide-up-leave-to { .slide-up-enter, .slide-up-leave-to {
max-height: 0; max-height: 0;
} }
</style> </style>
<script> <script>
@@ -139,6 +139,9 @@ export default {
errorMessage: { errorMessage: {
type: String, type: String,
}, },
openStatus: {
type: Number,
},
}, },
data () { data () {
return { return {
@@ -149,6 +152,13 @@ export default {
}), }),
}; };
}, },
computed: {
isOpen () {
// Open status is a number so we can tell if the value was passed
if (this.openStatus !== undefined) return this.openStatus === 1 ? true : false;
return this.open;
},
},
methods: { methods: {
adjustPagePadding () { adjustPagePadding () {
let minPaddingBottom = 20; let minPaddingBottom = 20;
@@ -156,6 +166,10 @@ export default {
let standardPage = document.getElementsByClassName('standard-page')[0]; let standardPage = document.getElementsByClassName('standard-page')[0];
standardPage.style.paddingBottom = `${drawerHeight + minPaddingBottom}px`; standardPage.style.paddingBottom = `${drawerHeight + minPaddingBottom}px`;
}, },
toggle () {
this.open = !this.open;
this.$emit('toggled', this.open);
},
}, },
mounted () { mounted () {
// Make sure the page has enough space so the drawer does not overlap content // Make sure the page has enough space so the drawer does not overlap content

View File

@@ -1,3 +1,5 @@
import habiticaMarkdown from 'habitica-markdown';
export default { export default {
methods: { methods: {
/** /**
@@ -74,9 +76,8 @@ export default {
}, },
markdown (val) { markdown (val) {
if (!val) return; if (!val) return;
// @TODO: Implement markdown library let parsedMarkdown = habiticaMarkdown.render(val);
// let parsed_markdown = $filter("markdown")(val); this.notify(parsedMarkdown, 'info');
// this.notify(parsed_markdown, 'info');
}, },
mp (val) { mp (val) {
this.notify(`${this.sign(val)} ${this.round(val)} ${this.$t('mana')}`, 'mp', 'glyphicon glyphicon-fire'); this.notify(`${this.sign(val)} ${this.round(val)} ${this.$t('mana')}`, 'mp', 'glyphicon glyphicon-fire');

View File

@@ -76,7 +76,10 @@ export default function () {
hideHeader: false, hideHeader: false,
viewingMembers: [], viewingMembers: [],
openedItemRows: [], openedItemRows: [],
castingSpell: false, spellOptions: {
castingSpell: false,
spellDrawOpen: true,
},
}, },
}); });